Search code examples
javascriptreactjssortingreact-component

React - sort array of child components with state


Currently I'm working on a react project, but I'm seeing some unexpected behavior when sorting an array of stateful child components.

If I have a parent component

export function Parent(){
  const [children, setChildren] = useState([
      {name:'Orange',value:2},
      {name:'Apple',value:1},
      {name:'Melon',value:3}
  ])
  var count = 0
  function handleSort() {
      var newChildren=[...children]
      newChildren.sort((a,b)=>{return a.value-b.value})
      setChildren(newChildren)
  }
  return (
      <div>
          <button onClick={handleSort}>Sort</button>
          {children.map((child) => {
            count++
            return(<ChildComp key={count} details={child}/>)
          })}
      </div>
  )
}

And a child component

function ChildComp(props){
  const[intCount,setIntCount] = useState(0)
  function handleCount(){
      setIntCount(intCount+1)
  }
  return (
      <div>
          <p>{props.details.name}</p>
          <button onClick={handleCount}>{intCount}</button>
      </div>
  )
}

When the page first renders everything looks great, three divs render with a button showing the number of times it was clicked and the prop name as it was declared in the array. I've noticed that when I sort, it sorts the props being passed to the child components which then rerender, but the intCount state of the child component stays tied to the original location and is not sorted. is there any way to keep the state coupled with the array element through the sort while still maintaining state data at the child level, or is the only way to accomplish this to raise the state up to the parent component and pass a callback or dispatch to the child to update it?


Solution

  • The count is not is not sorted. It just got updated when you sorted.

    Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity

    Every time you sort, key stay the same, as you use count.

    Try using value as key

    export function Parent(){
      // ....
      return (
          <div>
              <button onClick={handleSort}>Sort</button>
              {children.map(child => {
                return <ChildComp key={child.value} details={child}/> // key is important
              })}
          </div>
      )
    }
    

    More info: https://reactjs.org/docs/lists-and-keys.html#keys