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>
);
};
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With