Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Component not updating on Map (dictionary) state change using hooks

I have a child component that is supposed to display names based on a visibility filter with checkboxes. I use a dictionary to keep track of the checked state for each name. However, when I update the dictionary the child does not update.

Here is an example: https://codesandbox.io/s/8k39xmxl52

These are the components:

const App = () => {
  const [names, setNames] = useState(seedNames);
  const [hidden, setHidden] = useState(new Map());

  const handleHidden = e => {
    const name = e.target.name;
    const hidden = e.target.checked;

    setHidden(hidden.set(name, hidden));
  };

  return (
    <div className="App">
      <VisibilityFilter
        names={names}
        hidden={hidden}
        handleHidden={handleHidden}
      />
      <DisplayNames names={names} hidden={hidden} />
    </div>
  );
};

const VisibilityFilter = ({ names, hidden, handleHidden }) => {
  return (
    <div>
      {names.map(name => (
        <div key={name}>
          <input
            type="checkbox"
            name={name}
            checked={hidden.get(name)}
            onChange={handleHidden}
            defaultChecked
          />
          <span>{name}</span>
        </div>
      ))}
    </div>
  );
};


const DisplayNames = ({ names, hidden }) => {
  const visibleNames = names.filter(name => !hidden.get(name));

  return (
    <div>
      {visibleNames.map(name => (
        <div key={name}>{name}</div>
      ))}
    </div>
  );
};
like image 324
Travis S. Avatar asked Dec 23 '22 00:12

Travis S.


1 Answers

The use of immutable state is idiomatic to React, it's expected that simple types like plain objects and arrays are used.

Map set returns the same map, while useState supports only immutable states. In case setter function is called with the same state, a component is not updated:

setHidden(hidden.set(name, hidden))

The state should be kept immutable:

setHidden(new Map(hidden.set(name, hidden)))

This may introduce some overhead and defy possible benefits of ES6 Map. Unless Map features like strict item order and non-string keys are in demand, it's preferable to use plain object for the same purpose.

like image 53
Estus Flask Avatar answered Dec 25 '22 22:12

Estus Flask