0

How to fully replace one array by new in react useState();

For example how right to do this:

 const [colors, setColors] = useState(['#FF9A00', '#6276d5', '#18B8FB']);
 const onChangeColors = (newValue) => {
   setColors(prevState => [...newValue]);
 }
  return (<div style={{ width: '500px', margin: 'auto' }}>
  <h2>Current Color:</h2>
  {
    colors.map((color) => (<p>{color}</p>))
  }
    <ColorPicker colors={colors} onChange={newValue => onChangeColors(newValue)}/>
  </div>);

Function onChange of component ColorPicker returned array of strings for example: ['#bbbe41', '#7c67cf', '#70a385']

1
  • Off Topic, but you should take a look at the section Lists and Keys in the react documentation. Imo. the best solution here is to use the array-index as a key for the colors. Commented Jan 19, 2023 at 17:47

3 Answers 3

2

What is mutation?:

  • In essence, the concept of mutability describes whether or not the state of an object can be modified after it has been declared.

  • Numbers, strings, and boolean values are immutable, meaning unchangeable or “read-only in Javascript. Hovewer, it is technically possible to change the content of object (therefore arrays itself, which causes mutation.

Why not to mutate?:

  • There're couple different points why not to mutate data at all but, it's plainly more of stritctly applied best practice in order to not to cause another possible problem(s).

Then what to do?:

  • In order to achieve immutability with useState hook (or similarly setState method with class component), it's needed to be setting state via creating a new object.

  • Incase it's desired to keep previous state of an array within new one, previous state should be kept e.g. iterating over with a spread operator ...prevState. And only after then, new value(s) should be placed right after it like below;

const onChangeColors = (newValue) => {
   setColors(prevState => [...prevState, ...newValue]);
 }
  • Incase you don't want to keep the previous state of the array, then implementation is like below;
const onChangeColors = (newValue) => {
   setColors([...newValue]);
 }

To be short, the only thing for you to do differently is either;

  • If you want previous state of an array, copying the previous state before adding the new value to new returning array,
  • or only copying the new value into new returning array with setState function.
Sign up to request clarification or add additional context in comments.

4 Comments

"What is mutation?" OP neither does nor wants to mutate anything. "Why not to mutate?" because it's off topic? "setting state via creating a new object" how about using the new object we receive newValue? "the only thing for you to do differently is keeping the previous state before adding the new value" but OP explicitely does NOT want to keep the previous state.
@Thomas as per your last sentence "but OP explicitely does NOT want to keep the previous state", where did you assume this?
I get this from the "fully replace" in OPs first sentence "How to fully replace one array by new in react useState()"
I'll edit my question but your answer also does not present an answer since it's not preferred way of updating state in React @Thomas.
0

What you're doing is right. But if you wanna simplify further use a inline arrow function:

  const [colors, setColors] = useState(['#FF9A00', '#6276d5', '#18B8FB']);

  return (

 <div style={{ width: '500px', margin: 'auto' }}>
  <h2>Current Color:</h2>
  {
    colors.map((color) => (<p>{color}</p>))
  }
    <ColorPicker colors={colors} onChange={newValue => setColors(newValue)}/>
  </div>);

1 Comment

enquirer asks about best practice of using arrays with useState, and furthermore your answer removes the only necessary line to be edited.
0

How to fully replace one array by new in react useState();

by just setting it setState(newValue);


Let's go step by step:

  • [...newValue] this creates a copy of newValue. But newValue is already a new value (I'd assume by the name). So we don't need to copy the array.

  • which leaves us with setColors(prevState => newValue). but since we don't interact with prevState we don't need the function at all and can just pass the newValue.

  • now we're at const onChangeColors = (newValue) => { setColors(newValue); } but do we really need onChangeColors? All it does is forward the argument it gets to setColors. We can simply replace it: const onChangeColors = setColors;

  • onChange={newValue => onChangeColors(newValue)} that's the same as the step before, this function is also just forwarding the argument.

which effectively leaves us with: <ColorPicker colors={colors} onChange={setColors} />

But that's for this special case where onChange passes the new value, not like an event-object and you want to replace the old state, not append to it or something.

const [colors, setColors] = useState(['#FF9A00', '#6276d5', '#18B8FB']);

return (<div style={{ width: '500px', margin: 'auto' }}>
  <h2>Current Color:</h2>
  {
    colors.map((color, index) => (<p key={index}>{color}</p>))
  }
  <ColorPicker colors={colors} onChange={setColors} />
</div>);

3 Comments

I assume you should read React docs in order to understand why it should not be used as unlike setState(newValue); and preferred as setColors([...newValue]) incase previous state of the array not desired to be kept.
@ErhanYaşar I'm doing fine on both topics, react and mutation. But I don't understand your point. setState(newValue) will overwrite the current state with newValue while setColors([...newValue]) will overwrite the current state with a copy of newValue; basically newValue2. What's the point of creating that copy of a new value? to get a newer one? That's like printing out a PDF and then making a copy of the printout just to make sure that the PDF document isn't changed when you write on the printout.
Well that made me think I should be starting from the pure functions for my answer, before mentioning why not to mutate? and therefore other titles. My point is ideally having setState as a pure function which is best practice like not declaring global variables even it may not be causing error in most questions/cases. Instead of using same reference to an object with setState(newValue), it's better engineering practice to return setState([...newValue]) as per it's preferred to be used in a same mentality with redux/reducers (not to mutate but returning a new state).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.