Reputation: 43
I want to highlight the words that are in the "highlight" elements in the "text" element sentence. I can successfully highlight one sentence but I'm not able to concatenate two or more sentences together. I'm only able to show one sentence and it's highlighted word with the code:
this.setState({
text: result[0].text,
highlight: result[0].highlight,
});
But not more than more sentence at once. I want to dynamically concatenate as many sentences as there are in the api with the highlighted words. I tried setting the state to text: result[].text
and highlight: result[].highlight
but it gave me errors. As you can see in this sandbox, only when you do result[0].text
or result[1].text
, you get the different results but I want to concatenate all the sentences that are in the api dynamically supposing that I will have more sentences in the future.
The react code looks like this:
import React, { Component } from "react";
import { render } from "react-dom";
import "./App.css";
const stripChars = word => word.replace(/[\W_]+/g, "");
class App extends Component {
state = {
text: "The gun is a dangerous weapon, don't kill anyone",
highlight: ["gun", "kill"]
// text: "",
// highlight: []
};
componentDidMount() {
fetch("https://api.myjson.com/bins/1ep1fh")
.then(res => res.json())
.then(result => {
console.log(result);
this.setState({
text: result[0].text,
highlight: result[0].highlight
});
});
}
render() {
const { text, highlight } = this.state;
const words = text.split(" ");
return (
<div>
{words.map((word, i) => (
<span key={i}>
<span
className={highlight.includes(stripChars(word)) && "highlight"}
>
{word}
</span>
</span>
))}
</div>
);
}
}
export default App;
The CSS file:
.highlight{
background: red;
}
Upvotes: 2
Views: 1421
Reputation: 1631
Replacing the central part of your code with something similar to this should fix it:
fetch("https://api.myjson.com/bins/1ep1fh")
.then(res => res.json())
.then(result => {
let text = '';
let highlights = [];
// This will iterate over every entry in your result
for(const r of result) {
// The method will be executed for every entry, called r
text += r.text;
highlights.push(...r.highlight);
}
this.setState({
text: text,
highlight: highlights
});
});
}
This is very similar to @Dyo's approach, but it should be a little bit more efficient. He creates a new copy of the whole highlight array plus the entries to add in each iteration, while in this example, we use the Array.push
method. This only adds the new values while not duplicating the original values.
Upvotes: 1
Reputation: 4464
You have to iterate over your api results in order to concatenate them :
componentDidMount() {
fetch("https://api.myjson.com/bins/1ep1fh")
.then(res => res.json())
.then(result => {
console.log(result);
let text = "";
let highlight = [];
for (const item of result) {
text += item.text + '\n';
highlight = [...highlight, ...item.highlight];
}
this.setState({
text,
highlight
});
});
}
Edit: some code explanations
highlight = [...highlight, ...item.highlight];
Yes, this is the array spread operator here to create a single array with all words to highlight. (For each loop iteration, it spreads all words from the actual item's highlights in the loop, and also spread the old ones);
You can also do it like this :
for (const word of item.highlight) {
highlight.push(word);
}
let text = "";
let highlight = [];
This is just variable init, these are new ones, I could name them differently (I should have named them concatenatedTexts
and concatenatedHighlights
to avoid confusion)
Yes, the state is erased, if you want to keep your initial state and concatenate it too you can change setState
like this :
this.setState(prevState => ({
text: prevState.text + "\n" + text,
highlight: [...prevState.highlight, ...highlight]
}));
Upvotes: 1
Reputation: 7256
You can use Array.Map
and join()
in your api call for iterate and flat the array :
componentDidMount() {
fetch("https://api.myjson.com/bins/1ep1fh")
.then(res => res.json())
.then(result => {
let texts = result
.map((el, i) => {
return el.text;
})
.join("");
let highlights = result
.map((el, i) => {
return el.highlight;
})
.join("").split(",");
console.log(highlights);
this.setState({
text: texts,
highlight: highlights
});
});
}
Upvotes: 2