0

I have the following setup to render specific parts of the state as {this.state.text}. It works well enough on it's own, but not if I map it from an object. How do I get the mapped result to reference the state?

object

const data = [
  "{this.state.parameters.number} Tips to Get {this.state.parameters.goal}",
  "Your Search For {this.state.parameters.goal} Ends Here"
]

state

this.state = {
      parameters: {
        audience: '{Audience}',
        goal: '{Goal}',
        number: 6
      },
      subjectData: data
    }
}

map

const subjectLines = this.state.subjectData.map((result, index) =>
  <li key={index}>{result}</li>
)

The result of map() doesn't seem to reference the state at all.

result


{this.state.parameters.number} Tips to Get {this.state.parameters.goal}
Your Search For {this.state.parameters.goal} Ends Here

Whereas the expected result would be:

6 Tips to Get {Goal}
Your Search for {Goal} Ends Here
PaulVO
  • 309
  • 3
  • 13
  • try here, this explains why this doesn't work and also a way to do this with backticks and $ https://stackoverflow.com/questions/39523040/concatenating-variables-and-strings-in-react – hobomaan Aug 12 '20 at 19:12
  • Does the `data` value comes as a `prop` to your component? – Prathap Reddy Aug 12 '20 at 20:02

2 Answers2

1

You need additional method that replaces variable names with their values. For example,

function getProcessedString(s) {
  return s.replace('{this.state.parameters.number}', this.state.parameters.number).replace('{this.state.parameters.goal}', this.state.parameters.goal);
}

And on map,

const subjectLines = this.state.subjectData.map((result, index) =>
  <li key={index}>{getProcessedString(result)}</li>
)
Hayden S.
  • 742
  • 4
  • 10
1

By default, React DOM escapes any values embedded in JSX before rendering them to prevent XSS (cross-site-scripting) attacks. Thus it ensures that you can never inject anything that’s not explicitly written in your application. Check here for more details

You can change your data array values as below and use Object.keys and reduce to get the desired result

const data = [ "#number# Tips to Get #goal#", "Your Search For #goal# Ends Here" ];

....

const { parameter, subjectData } = this.state;
...

const subjectLines = subjectData.map((result, index) => <li key={index}>{Object.keys(parameter).reduce((acc, key) => acc.replace(`#${key}#`, parameter[key]), result}</li>)
Prathap Reddy
  • 1,688
  • 2
  • 6
  • 18
  • Thanks for the great answer @prathap-reddy. How would this change if there's more than just a single level within that data though? For example: ``` { "content": [ { "text" : "#number# Tips to Get #goal#", "types" : [ "email"] }, { "text" : "Your Search For #goal# Ends Here", "types" : [ "ad", "email" ] } ] } ``` – PaulVO Aug 19 '20 at 21:29
  • 1
    You can loop through the nested object `recursively` and replace with `state` data only if you encounter `string` as a value. Alternatively, you can use libraries like `loadsh` (_get, _set methods). If you use library you need to maintain an array of object `nested path` and `value` to be replaced in a separate object like `mapping`. – Prathap Reddy Aug 20 '20 at 04:08