最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - What exactly is prevState in a functional component's setState? - Stack Overflow

programmeradmin6浏览0评论

Returning the (changed) previous state within a setState that one gets from the useState hook doesn't seem to alter state. Run the following straight forward snippet

function App(){
  const [state, setState] = React.useState([{x: 0}])
  function changeCount(){
    setState(prevState => {
      console.log('before', prevState[0])
      const newState = [...prevState]
      newState[0].x += 1 //the shallow copy newState could potentially change state
      console.log('after', prevState[0])//here x gets bigger as expected
      return prevState //instead of newState we return the changed prevState
    })
  }
  //checking state shows that x remained 0
  return <div className='square' onClick={changeCount}>{state[0].x}</div>
}
ReactDOM.render(<App/>, document.getElementById('root'))
.square{
  width: 100px;
  height: 100px;
  background: orange;
}
<script src=".8.6/umd/react.production.min.js"></script>
<script src=".8.6/umd/react-dom.production.min.js"></script>
<div id='root'></div>

Returning the (changed) previous state within a setState that one gets from the useState hook doesn't seem to alter state. Run the following straight forward snippet

function App(){
  const [state, setState] = React.useState([{x: 0}])
  function changeCount(){
    setState(prevState => {
      console.log('before', prevState[0])
      const newState = [...prevState]
      newState[0].x += 1 //the shallow copy newState could potentially change state
      console.log('after', prevState[0])//here x gets bigger as expected
      return prevState //instead of newState we return the changed prevState
    })
  }
  //checking state shows that x remained 0
  return <div className='square' onClick={changeCount}>{state[0].x}</div>
}
ReactDOM.render(<App/>, document.getElementById('root'))
.square{
  width: 100px;
  height: 100px;
  background: orange;
}
<script src="https://cdnjs.cloudflare./ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<div id='root'></div>
By clicking the square we trigger setState. Within setState we make a shallow copy newState of the previous state. By changing the copy we change the prevState (maybe unintentionally) as the console confirms. Returning the changed previous state form setState however doesn't change the state as the count remains 0. If we were to return the newState, the behavior would be as expected.

Repeating this, shows that prevState gets bigger, it just doesn't seem to represent the previous state anymore.

Why is that? I made this minimal example on codepen...

Share Improve this question edited Feb 7, 2020 at 5:26 Michael asked Feb 7, 2020 at 5:20 MichaelMichael 9588 silver badges19 bronze badges 9
  • thats a good question, trying to find out what is happening. – Tinu Jos K Commented Feb 7, 2020 at 5:40
  • @gaditzkhori it's a shallow copy, thats why both prevState and newState is modifying the same x value, and on each renders the prevState actually gets the updated previous value, then why can't we set it onto the state and why is it not displayed in the div? – Tinu Jos K Commented Feb 7, 2020 at 5:55
  • 1 setState is paring the previous state object to the object you're returning. If both these reference the same object, no render takes place. Despite the fact that prevState has been updated, it's still the same object. – FuriousD Commented Feb 7, 2020 at 5:58
  • 2 newState is a shallow copy but you changed x which is the same reference.React doesn't know that it is changed deeply and therefore doesn't rerender.so basicly it's pure js not some React magic.thats the whole idea of shallow rendering. – gadi tzkhori Commented Feb 7, 2020 at 6:02
  • 1 you are right! prevState gets updated as it should be, but no rerender takes place because of the deep change of the object. forcing a rerender by changing some extra dummy state variable shows that the count goes up correctly – Michael Commented Feb 7, 2020 at 6:53
 |  Show 4 more ments

1 Answer 1

Reset to default 5

Consider that object assignment is just a reference assignment, never a copy

obj1 = {x:42, y:99};
obj2 = obj1;   // obj1 and obj2 both reference the same object
obj1.x += 1;   
obj2.y += 1;
console.log(obj1.x, obj1.y);
console.log(obj2.x, obj2.y);  // prints the same thing since obj1 and obj2 are the same object

In the above example, obj1 is initialized to point to a new object with properties x and y. When obj2=obj1 is made, this is not a copy of obj1 into obj2, but rather obj1 and obj2 now reference the same object.

Hence, when the console.log statements print, they print the same thing because they are both printing property values from the same object.

Similarly, the additional reference to the original object is being made when the shallow copy from prevState to newState occurrs.

obj = {x:42, y:99};
prevState[0] = obj;     // prevState[0] is a reference to obj.  prevState[0] and obj point to the same exact thing

newState = [...prevState];  // shallow copy, but newState[0] is an object reference.  newState[0] and prevState[0] both point to "obj"

newState[0].x += 1;         // is actually updating the original object assigned to prevState[0]
发布评论

评论列表(0)

  1. 暂无评论