
Size: a a a
componentDidMount
и useEffect
в одной картинкеcomponentDidMount
всегда вызывается в текущем кадре, а useEffect
— обычно в начале следующего)componentDidMount
это вызовет принудительное перевычисление стилей (это дорого). А в useEffect
не вызовет — браузер к тому моменту уже завершит кадр и перевычислит всё сам.useLayoutEffect
вызывается там же, где и componentDidMount
— в текущем кадре. Из-за этого код в useLayoutEffect
тоже может вызвать принудительное перевычисление. Это главная причина, по которой React не рекомендует использовать useLayoutEffect (если вы только не знаете наверняка, зачем он вам).useEffect
обычно вызывается в следующем кадре — но не всегда. Если у React запланировано несколько рендеров подряд, он будет вызывать useEffect
сразу перед следующим рендером, не дожидаясь окончания кадра. См. документацию → «it’s guaranteed to fire before any new renders»/* pages/my-page.js */
export const config = {
unstable_runtimeJS: false
}
export default () => <h1>My page</h1>
const userId = useSelector(state => state.selectedUser.id)
useSelector
вызывает перерисовку компонента каждый раз, когда данные меняются. Это полезно — если пользователь поменялся, мы хотим, чтобы и его аватарка перерисовалась:userId
не в самом компоненте, а в обработчике события? Тогда компонент будет перерисовываться зря. userId
будет меняться, но DOM будет оставаться таким же:<ChangeUserAvatarButton />
дорогой, а выбранный пользователь меняется часто, это может быть проблемой. useSelector
без проблем заменяется на useStore
:useStore
вернёт стор — и всё. Он не будет извлекать какие-то конкретные поля из стора. Он не будет перерисовывать компонент, когда что-то меняется.userId
прямо из store.getState()
. Никаких лишних ререндеров.<link rel="stylesheet">
загрузились, можно отрендерить страницу». А Typekit ему такой: «пха, погоди, у меня тут ещё одни стили, не хочешь и их загрузить сначала?» И всё — вместо того, чтобы загрузить всё за раз, браузер загружает новые стили по второму кругу.