Search code examples
javascriptreactjsreact-admin

Storing derived variables in react state doesn't work


I'm trying to write a component that's basically a transferlist, but for the sake of this problem I simplified it a lot.

See below example: the react-admin component gets 2 inputs: a sub-list of selected items record[source] (source points to a property on the record object, this is react-admin specific), and a list with all possible items allItems. I want the component to display 2 lists: the list of selected items, and a list of NOT selected items. The list of selected items is given, and I calculate the list of NOT selected items by simply filtering the list containing all items and removing the selected ones.

However for some reason (definitely related to my limited javascript/react experience), I can't get this to work.

What I'm seeing in the below code is that the left variable is working just fine, and displaying the selected items. However the right variable always seems to be empty, event though I check that the unselected variable contains the wanted list when doing the useState(unselected) call.

Note: the items are just strings, and I can see that the variable unselected contains the items I want just fine. So the problem is related to using state, not calculating the unselected list.

I'm pretty sure I'm just bumping into the limits of my React / Redux state knowledge here, but I'm not sure why this is happening and how to fix it. Any input very welcome!

import React, { useState } from 'react';

export const TransferList = ({record, source, allItems}) => {

  var unselected = allItems.filter(name => !(record[source].includes(name)));
  const [left, setLeft] = useState(record[source]);
  const [right, setRight] = useState(unselected);

  return (
    <div>
      Selected:
      <ul>
        { left.map(s => <li>{s}</li>) }
      </ul>
      Unselected:
      <ul>
        { right.map(s => <li>{s}</li>) }
      </ul>
    </div>
  );
}

Solution

  • I just get somehow your allItems is updated then your should useEffect to track the update from the allItems:

    useEffect(()=>{
      const unselected = allItems.filter(name => !(record[source].includes(name)));
      setRight(unselected)
    },[allItems])
    

    Please check if it work