Как избежать использования useEffect на каждый рендер? - PullRequest
1 голос
/ 17 апреля 2019

Я создаю пользовательский хук, который принимает объект и, в свою очередь, вызывает useEffect. Объект может содержать встроенные функции.

const stuff = useValidation({
  fields: {
    username: { /* more nested objects */ }
  },
  onSubmit: () => alert('submitted'),
});

Реализация ловушки выглядит следующим образом:

function useValidation(config) {
  const [state, dispatch] = useReducer(validationReducer);
  useEffect(() => {
    validateFields(config.fields, state);
  }, [config.fields, state]);
}

Это еще не все ( вот фактическая реализация ), но это соответствующие части.

Когда я создаю встроенный объект, useEffect работает непрерывно. Это происходит потому, что React использует ссылочное равенство (а не глубокое равенство), чтобы проверить, изменился ли материал.

Я могу «исправить» это, либо поместив мою конфигурацию в useMemo, либо переместив ее за пределы метода рендеринга. И то и другое очень плохо для разработчиков.

Я попробовал библиотеку Кента С. Доддса use-deep-compare-effect, но, поскольку я разрешил встроенные функции стрелок в моей конфигурации, она не "работает".

Предпочтительно, я бы хотел, чтобы пользователь мог вводить встроенный объект и как-то разрешать любые изменения.

Как я могу решить это?

Ответы [ 2 ]

1 голос
/ 17 апреля 2019

Мне кажется, что useEffect вызывается при каждом рендеринге, потому что конфигурация, которую вы передаете useValidation, создается на лету каждый раз. Я бы посоветовал перевести это в состояние где-нибудь либо в вашем компоненте, где вы используете useValidation, либо в самом useValidation, например:

function useValidation(config) {
  const [storedConfig, setStoredConfig] = useState(config);
  const [state, dispatch] = useReducer(validationReducer);

  useEffect(() => {
    validateFields(config.fields, state);
  }, [storedConfig.fields, state]);
}

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

0 голосов
/ 17 апреля 2019

похоже, что это только синтаксическая ошибка в вашем коде.

ваша функция должна выглядеть следующим образом

function useValidation(config) {
 const [state, dispatch] = useReducer(validationReducer);
  useEffect(() => {
    validateFields(config.fields, state);
  }, [config.fields, state])
}
...