@Vadim1899

Правильно ли я понимаю причину ререндеров в react+redux?

Привет! Есть приложение на react+redux, в котором есть почтовая форма. Данные этой формы хранятся в store в отдельном слайсе/редьюсере:
{
   ...
   form: {
      name: '',
      surname: '',
      email: '',
      agree: false,
   }
}


В контейнере получаю эти значения вот так:
const { name, surname, email, agree } = useSelector((state) => state.user.form);


и далее вставляю эти значения в инпуты, чекбоксы и тд:
<input value={email} onChange={(e) => dispatch(setEmail(e.target.value))}


но столкнулся с проблемой ререндеров. установил плагин для хрома, который подсвечивает элементы при их ререндере и вот что заметил: если вводим что-то в инпут email, например, то ререндерятся все инпуты - name, surname, agree. Так ведь не должно быть? По логике мы изменяем состояние только для одного инпута (значение value) - только он и должен перерисовываться.

полагаю проблема в том, что когда получаю значения из стора через useSelector, я беру не конкретное значение, а весь объект form и потом делаю его спред на name, surname, email, agree. и когда меняем любое из значений, useSelector триггерится для всех инпутов.

попробовал для каждого поля по отдельности доставать значение:
const name = useSelector((state) => state.user.form.name);
const surname = useSelector((state) => state.user.form.surname);
const email = useSelector((state) => state.user.form.email);
const agree = useSelector((state) => state.user.form.agree);


но все равно все инпуты подсвечиваются -> перерисовываются. в чем может быть дело?

P.S. не считаю что это преждевременная оптимизация, которую не нужно делать. как минимум хочется разобраться в таком поведении

UPD: если каждый инпут обернуть в useMemo и в зависимости положить значение инпута (email/name/surname), то лишних ререндеров не будет. но мне кажется что это не ок
  • Вопрос задан
  • 193 просмотра
Пригласить эксперта
Ответы на вопрос 1
@i1yas
Предположу что вы делаете так:
const MyForm = () => {
    const name = useSelector((state) => state.user.form.name);
    const surname = useSelector((state) => state.user.form.surname);
    const email = useSelector((state) => state.user.form.email);
    const agree = useSelector((state) => state.user.form.agree);

    ...
}

В этом случае даже один селектор тригернет ререндер компонента MyForm

Нужно переработать форму так, чтобы компонент каждого поля внутри себя использовал useSelector:
const Field = ({ name, ... }) => {
    const value = useSelector(...);
    ...
}
const MyForm = () => {
    return (
       <FormContainer ...>
          <Field name="name"/>
          <Field name="surname"/>
          <Field name="email"/>
          ...
       </Form>
    )
}


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

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы