React - how to 'split' an array to give line breaks - reactjs

I have an array, let's say:
["One", "Two", "Three"]
And I'd like to render it as a string on separate lines with "<br/>" between each element as:
One<br/>Two<br/>Three
so that they'll render as separate lines. What I'd use in a text-based system would be something like:
my_array.join("\n")
So what I want is the equivalent of:
my_array.join(<br/>)
But that doesn't work in something like:
return <div>{my_array.join(<br/>)}</div>;
as it returns objects instead of what I'm looking for:
One[object Object]Two[object Object]Three
Note that I DON'T want a trailing <br/> at the end - I understand I could use a map for that.
To save you reading further, the solution I used is:
my_array.map((item, index) => index ? <><br/>{item}</> : <>{item}</>)
which does use a map but utilises the index to place a <br/> before every element but the first.

Something like this should work:
["One", "Two", "Three"].map((item, index) => {
if (index === 0) {
return <>{item}</>
}
return <><br/>{item}</>
})

I think you can edit the each string array value and put the line break in to it .
you need to use map function.
<div>{my_array.join.map((item, index) =>
<span> {item}<br/></span>
)}</div>

This is how you would do it:
function MyComponent(props) {
let arr = ["One", "Two", "Three"];
return (
<div>
{[...arr.map(item => <div key={item}>{item}</div>), <br key={'br'}/>]}
</div>
);
}
export default MyComponent;
Don't forget that it is important to include a unique key prop for each element in the array to ensure that React can efficiently update the list.
Hope it helped!

Related

Conditional classes on single instances of component within a loop

I have a loop of components that make a grid and I want some instances to have a background color change triggered by adding a class.
This question gave me ideas but I've yet to get them to work.
I have this basic markup in it.
<div className={`box ${(this.state.backgroundColor ? 'backgroundColor' : null)}`} key={i}>
</div>
And I have an array of the indexes representing the component instances that I want the color changed on
let indexes = [101, 178, 232, 545]
Currently I am doing it with plain JS, via document.querySelector('.box:nth-of-type(101'), but as this method bypasses React I want to change it.
Based on the other question I tried making an array of all the components and setting that to state, then looping through and using the indexes. I don't know how to "access" the component like this and get $$typeof: Symbol(react.element) etc
let compArr = []
this.arr.map((i) => {
compArr.push(
<div className={`box ${(this.state.backgroundColor ? 'backgroundColor' : null)}`} key={i}>
</div>
)
})
this.setState({
compArr: compArr
})
Then later loop over indexes:
indexes.map(index => {
this.state.compArr[index] ===> ??stuck here??
})
Expected Output: So on an array of three instances, say I want the second one only to have the class of backgroundColor:
<div className='box' </div>
<div className='box backgroundColor'</div>
<div className='box'</div>
Only in my case, I want the instances to correlate with the indexes array
How can I set the conditional class to true in those instances I have in the array? Say I have like 500+ instances total.
If I understand you correctly this is proably what you're looking for...
let indexes = [101, 178, 232, 545]
let compArr = this.arr.map((obj, i) => {
return (
<div
className={`box${( indexes.includes(i) ? " backgroundColor" : "")}`}
key={i}
>
</div>
);
})
this.setState({
compArr: compArr
})
If your goal is only to return the given div with the className backgroundColor for every element in this.arr with its index included in the indexes array then...
You only need to iterate over the array once and can perform all the necessary logic you're currently doing performing in two.
You don't need to use Array.push() to an outside collector when using any of the pure functions like map() or reduce() because they return a new version of whatever array is iterated over.
If for whatever reason you want a distinct array of <div>s with an index in indexes then you should use reduce...
let compArr = this.arr.reduce((acc, obj, i) => {
if (!indexes.includes(i)) return acc;
return [
...acc,
<div className="box backgroundColor" key={i}></div>
)]
},[])

React save the value of current state and make it unchangeable

I am new to React and I have a problem considering saving the value of current state. I am not sure if it is possible.
To summarise, I have build up a function which returns a HTML element as below. The idea is to save a div on each click.
createQuestion(){
let CurrentQuestion=this.state.freetextinput;
return this.state.values.map((el, i) =>
<div key={i} className="QuestionBox">
{CurrentQuestion}
</div>
)
}
The value of freetextinput changes on each click. The idea is to save all the value of freetextinput. Say, the values of freetextinput are 1, 2, 3. I would like to have all of the three values:
1
2
3
However, I only get something like this:
3
3
3
I wonder, if there is a way to save/store the value of this.state.freetextinput, such that I can get all the three values.
The new question needs to be pushed into an array before it can be mapped. Might something like this work for you?
var savedQuestions = []
createQuestion(q){
savedQuestions.push(q)
this.setState({savedQuestions: savedQuestions}, () => {
var questionElements = this.state.savedQuestions.map((el, i) =>
<div key={i} className="QuestionBox">
{el}
</div>
)
})
return questionElements
}
Save every input of free text input into an array, that way you would get access to all the values:
You can check this code sandbox: https://codesandbox.io/s/j835121kv
You should map this.state.freetextinput directly :
Since freetextinput is a string, you will need to convert it to an array first using split
createQuestion(){
return this.state.freetextinput.split(', ').map(el =>
<div key={el} className="QuestionBox">
{el}
</div>
)
}
This will work if your string looks like : "1, 2, 3"
If your string is "123" then use split('') instead of split(', ')

Reactjs, how to instanciate object from array, and update render

I'm struggling with reactjs for no reason. I'm a little confused about the magic behind and I'm not able to perform a simple operation of adding object / removing object from an array and display it.
I my parent, I have a method which on click append a new element:
appendNewPma(){
var newPma = this.state.pma.slice();
newPma.push(PmaType1);
this.setState({pma:newPma})
}
then my render method is like that:
render() {
return (
<div>
<a className="waves-effect waves-light btn" onClick={this.appendNewPma}>new</a>
{this.state.pma.map((Item, index) => (
<Item
key = {index}
ref = {"pma" + index.toString()}
onDelete = {() => this.onDelete(index)}
title = {index}/>
))}
</div>
);
}
Append work fine, but my array doesn't contain an object to display but rather a magical function that I don't understand.
But when I try to delete an object:
onDelete(idx){
console.log(idx);
var pma = this.state.pma.slice();
pma.splice(idx, 1);
this.setState({pma:pma})
}
When I delete from the array, no matter what index I will remove, it will only remove the last object. I know my code is not ok, but I have no idea how you can render element for an array of object (here my array is list of function constructor).
It will work better if I could get a straight ref to my object. Of course, I tryed to removed from the ReactDom, but was complening I was not updating from the parent...
I just want a simple array push/pop pattern with update.
Thanks for your help
Try below code. hope so it solve your issue.
addToArray = (event) => {
this.state.pma.push({"name ": "xyz"});
this.setState(
this.state
)
}
removeFromArray =(index) => {
var updatedArr = this.state.pma.splice(index, 1);
this.setState({arr : updatedArr})
}

Render some text if array.filter returns 0 in React?

I have a filter on an array in the render function in a React component:
someArray.filter(item => {
if (item.name.includes(searchText))return true
}).map(item=>{
return <h1>{item.name}</h1>
});
How can I elegantly display some text along the lines of "No search results" when no items are being returned by the map function?
There are a few ways you can do this. You can use a ternary operator (and also shorten your callbacks):
const filtered = someArray.filter(item =>
item.name.includes(searchText)
);
//Then, in your JSX:
{
filtered.length > 0 ?
filtered.map((item, key) =>
<h1 key={key}>{item.name}</h1>
)
:
<h1>No search results</h1>
}
This checks if there are any filtered results. If so, it will map them to h1s that have the name of the item. If not, then it will simply render a single h1 with the text 'No search results'.
One possible way is, instead of putting this code directly inside JSX render method, put it inside a method and call that method from render.
Like this:
_filterItem(){
const arr = someArray.filter(item => item.name.includes(searchText))
if(!arr.length) return <div>No data found</div>;
return arr.map(item => <h1 key={/*some unique value*/}>{item.name}</h1>)
}
render(){
return(
<div>{this._filterItem()}</div>
)
}
Suggestion:
With filter and map you can use concise body of arrow function instead of block body, for more details check MDN Doc.
Short and concise:
someArray.map(({name}) => name.includes(searchText) && <h1>{name}</h1>)

React/JSX - How to render a list alphabetically

I am working on someone else's code and trying to figure out how to render a list alphabetically in React. I didn't write any of this and have very little knowledge of React, so please bear with me.
The ul looks like this:
<ul className="prod-group__filter__options" ref={(options) => this.options = options}>
{
filter.dropdown.map((option, index) => (
this.renderOption(filter, option, index)
))
}
</ul>
and the renderOption function, which obviously renders the list items looks like this:
renderOption(filter, option, index) {
return (
<li className="prod-group__filter__option" key={index}>
<label className="prod-group__filter__option__label">
<input name={filter.name}
type="checkbox"
defaultValue={option.slug}
checked={option.checked}
onChange={this.optionChangeHandler} />
{option.label}
</label>
</li>
);
}
The value I am trying to alphabetize is option.slug which is coming from a json list. Can anyone help me get a bit closer to rendering this list alphabetically?
It looks like filter.dropdown is your array of options. This array is passed to the .map() method which then runs a renderOption method in the given order.
Hence, you should sort the filter.dropdown array in your ul component code just before calling .map() on it.
You will have to sort option alphabetically using plain javascript before calling filter.dropdown.map... on it. I would advice using lodash function _.sortBy(option, 'slug'); where option is an array of objects with a property called slug then you can pass the sorted result to your map function.
In case anyone is interested, the solution was to sort the list items before calling .map() on it as both macbem and finch suggested. I used const to create an "items" constructor that I could then pass into the ul further down:
const items = [].concat(this.props.options)
.sort((a, b) => {
const One = a.slug.toUpperCase();
const Two = b.slug.toUpperCase();
return (One < Two) ? -1 : (One > Two) ? 1 : 0;
})
.map((option, index) => this.renderOption(name, option, index));
return (
<div className={classes}>
<a className="prod-group__filter__dropdown"
ref={(trigger) => this.trigger = trigger}
onClick={this.triggerClickHandler}>
{label}
</a>
<ul className="prod-group__filter__options" ref={options => this.options = options}>
{ items }
</ul>
</div>
);

Resources