Документация фактически гласит:
В любом случае, мы не рекомендуем этот шаблон и показываем его здесь только для полноты. Вместо этого предпочтительнее избегать передачи обратных вызовов вглубь .
Допустим, мы не можем избежать передачи обратных вызовов, тогда самым простым способом было бы использовать обратный вызов дляустановщик состояния: setSomeState(currentState=>....return something based on current state)
Я не уверен, как это будет вести себя при освобождении параллельного режима, но вот пример того, как вы можете использовать обратный вызов для установщика состояния:
const ParentContainer = () => {
//list is created and maintained in parent
const [list, setList] = React.useState([
{ id: 1, val: true },
{ id: 2, val: true },
]);
//simplest way to get current list is to pass a callback
// to the state setter, now we can use useCallback without
// dependencies and never re create toggle during this life cycle
const toggle = React.useCallback(
id =>
setList(list =>
list.map(item =>
item.id === id
? { ...item, val: !item.val }
: item
)
),
[]
);
return Parent({ list, toggle });
};
const Parent = ({ list, toggle }) => (
<div>
{list.map(item => (
<ItemContainer
key={item.id}
item={item}
//every item gets the same toggle function
// reference to toggle never changes during Parent life cycle
toggle={toggle}
/>
))}
</div>
);
//Added memo to make ItemContainer a pure component
// as long as item or toggle never changes the (render) function
// will not be executed
// normally a pure component should not have side effects so don't
// do side effects in pure compnents (like mutating rendered var)
// it is only to visibly display how many times this function was
// called
const ItemContainer = React.memo(function ItemContainer({
item,
toggle: parentToggle,
}) {
const rendered = React.useRef(0);
//toggling item with id 1 will not increase render for
// other items (in this case item with id 2)
// this is because this is a pure component and this code
// will not be executed due to the fact that toggle or item
// never changed for item 2 when item 1 changed
rendered.current++;
const toggle = React.useCallback(
() => parentToggle(item.id),
[item.id, parentToggle]
);
return Item({ toggle, item, rendered });
});
const Item = ({ toggle, item, rendered }) => (
<div
onClick={() => toggle(item.id)}
style={{ cursor: 'pointer' }}
>
<div>{item.val ? '[X]' : '[-]'}</div>
<div>times rendered:{rendered.current}</div>
</div>
);
//render app
ReactDOM.render(
<ParentContainer />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>