Как делать регидрацию при использовании nextjs и mobx?

Рейтинг: 1Ответов: 1Опубликовано: 17.03.2023

Не понимаю почему на next 13 версии, react-dom 18, react 18, useEffect срабатывает не при первом рендере. Приходится писать костыли в виде хука useIsFirstRender, для того что бы это работало:

export async function getServerSideProps({ query }) {
    const data = await productListStore.fetchProductsFilters(query)
    productListStore.setProductsFilter(data)
    return {
        props: {
            initialData: data,
        },
    }
}
const function useIsFirstRender(callback = () => {}) {
    const isFirst = useRef(true)

    if (isFirst.current) {
        isFirst.current = false
        callback()
        return true
    }

    return isFirst.current
}
const Page = ({ initialData }) => {
    useIsFirstRender(() => {
        productListStore.setProductsFilter(initialData)
    })
    // render jsx...
}
export default observer(Page)

Может кто подскажет адекватный способ работы с этим, в проекте большое количество сторов.

Ответы

▲ 0

В React 18 по умолчанию включен экспериментальный режим startTransition, который позволяет оптимизировать рендеринг и улучшить производительность. Одним из изменений является то, что эффекты useEffect не выполняются сразу после рендеринга компонента, а ставятся в очередь на выполнение. Это связано с тем, что startTransition может отложить некоторые изменения состояния, чтобы позволить браузеру выполнить другие задачи, такие как рендеринг анимации или пользовательских действий.

Если вы хотите, чтобы эффект useEffect выполнялся немедленно после первого рендеринга компонента, вы можете использовать второй аргумент useEffect, который определяет зависимости эффекта. Если этот массив зависимостей пустой, эффект будет выполняться только при первом рендеринге компонента.

В вашем случае, вы можете попробовать использовать следующий код:

const Page = ({ initialData }) => {
  useEffect(() => {
    productListStore.setProductsFilter(initialData)
  }, []) // <-- пустой массив зависимостей

  // render jsx...
}

export default observer(Page)

Если вы используете useEffect с асинхронными операциями, такими как fetch, вы можете увидеть другое поведение: эффект может не выполняться немедленно после первого рендеринга компонента, но начнет выполняться после того, как будет завершен fetch. В этом случае вам нужно использовать зависимости, которые определяют, когда эффект должен быть запущен. Например, если вы хотите, чтобы эффект запускался только при изменении initialData, вы можете использовать следующий код:

const Page = ({ initialData }) => {
  useEffect(() => {
    async function fetchData() {
      const data = await productListStore.fetchProductsFilters(query)
      productListStore.setProductsFilter(data)
    }
    fetchData()
  }, [initialData]) // <-- массив зависимостей с initialData

  // render jsx...
}

export default observer(Page)