#reactjs #react-hooks
#reactjs #реагирующие хуки
Вопрос:
Одним из преимуществ возможности использования shouldComponentUpdate
в компоненте класса React является возможность управлять отображением на основе условия, а не просто изменением значений состояния / prop.
Какой предпочтительный способ выполнить эту оптимизацию с использованием react hooks в функциональном компоненте?
В приведенном ниже примере компонент класса не выполняет повторное отображение, если он находится (или остается) в закрытом состоянии, даже если у него есть новые дочерние элементы.
class DrawerComponent extends React.Component {
static propTypes = {
children: PropTypes.any,
}
state = {
isOpen: false,
}
// only re-render if the drawer is open or is about to be open.
shouldComponentUpdate(nextProps, nextState) {
return this.state.isOpen || nextState.isOpen;
}
toggleDrawer = () => {
this.setState({isOpen: !this.state.isOpen});
};
render() {
return (
<>
<div onClick={this.toggleDrawer}>
Drawer Title
</div>
<div>
{this.state.isOpen ? this.props.children : null}
</div>
</>
)
}
}
Аналог функционального компонента (без оптимизации):
function DrawerComponent({ children }) {
const [isOpen, setIsOpen] = useState(false);
function toggle() {
setIsOpen(!isOpen);
}
return (
<>
<div onClick={toggle}>
Drawer Title
</div>
<div>{isOpen ? children : null}</div>
</>
);
}
Ответ №1:
В этом примере, на мой взгляд, нет необходимости в shouldComponentUpdate
оптимизации. Это уже будет быстро, поскольку вы не выполняете рендеринг children
, когда ящик закрыт. Стоимость запуска функционального компонента будет довольно незначительной.
Тем не менее, если вы действительно хотите реализовать эквивалентное поведение в функциональном компоненте, вы могли бы использовать React.memo
и предоставить пользовательскую areEqual
функцию: https://reactjs.org/docs/react-api.html#reactmemo.
Комментарии:
1. Насколько я помню, учитывая ваш пример, вызов
setIsOpen
с одним и тем же значением дважды не вызовет повторного рендеринга. Значение должно пройти строгую проверку на равенство===
.2. Я думаю, вам понадобится
useCallback
для этого. Однако я не пытаюсь перехватить повторный рендеринг изsetIsOpen
, скорее, изменение дочерних элементов во времяisOpen === false
3. Я собрал этот codesandbox вместе, чтобы продемонстрировать, что передача того же значения в setX не вызывает повторного отображения, даже с массивом, в котором есть новый элемент: codesandbox.io/s/0ypy38q9rw
4. @JamieKudla если бы у вас была веская причина, вы могли бы запомнить дерево элементов, которое вы возвращаете в своей функции, и вернуть предыдущее значение, если ящик закрыт. Тогда React не будет утруждать себя дифференцированием или иной обработкой выходных данных. В качестве альтернативы у вас может быть дочерний компонент, который получает оба
children
иisOpen
в качестве реквизита и предотвращает рендеринг сReact.memo
, как описано. Однако в данном сценарии это действительно перебор.5. @Joru Не относится конкретно к этому сценарию, просто любопытно, как можно обработать что-то подобное. Я думаю, что создание нового компонента, который получает значения состояния в качестве реквизита и обрабатывает через
memo
, — это ответ, который я ищу, спасибо!.