У меня есть форма с несколькими слоями дочерних компонентов.Состояние формы поддерживается на самом высоком уровне, и я передаю функции в качестве реквизита для обновления верхнего уровня.Единственная проблема с этим - когда форма становится очень большой (вы можете динамически добавлять вопросы), каждый отдельный компонент перезагружается при обновлении одного из них.Вот упрощенная версия моего кода (или кодов и коробки: https://codesandbox.io/s/636xwz3rr):
const App = () => {
return <Form />;
}
const initialForm = {
id: 1,
sections: [
{
ordinal: 1,
name: "Section Number One",
questions: [
{ ordinal: 1, text: "Who?", response: "" },
{ ordinal: 2, text: "What?", response: "" },
{ ordinal: 3, text: "Where?", response: "" }
]
},
{
ordinal: 2,
name: "Numero dos",
questions: [
{ ordinal: 1, text: "Who?", response: "" },
{ ordinal: 2, text: "What?", response: "" },
{ ordinal: 3, text: "Where?", response: "" }
]
}
]
};
const Form = () => {
const [form, setForm] = useState(initialForm);
const updateSection = (idx, value) => {
const { sections } = form;
sections[idx] = value;
setForm({ ...form, sections });
};
return (
<>
{form.sections.map((section, idx) => (
<Section
key={section.ordinal}
section={section}
updateSection={value => updateSection(idx, value)}
/>
))}
</>
);
};
const Section = props => {
const { section, updateSection } = props;
const updateQuestion = (idx, value) => {
const { questions } = section;
questions[idx] = value;
updateSection({ ...section, questions });
};
console.log(`Rendered section "${section.name}"`);
return (
<>
<div style={{ fontSize: 18, fontWeight: "bold", margin: "24px 0" }}>
Section name:
<input
type="text"
value={section.name}
onChange={e => updateSection({ ...section, name: e.target.value })}
/>
</div>
<div style={{ marginLeft: 36 }}>
{section.questions.map((question, idx) => (
<Question
key={question.ordinal}
question={question}
updateQuestion={v => updateQuestion(idx, v)}
/>
))}
</div>
</>
);
};
const Question = props => {
const { question, updateQuestion } = props;
console.log(`Rendered question #${question.ordinal}`);
return (
<>
<div>{question.text}</div>
<input
type="text"
value={question.response}
onChange={e =>
updateQuestion({ ...question, response: e.target.value })
}
/>
</>
);
};
Я пытался использовать useMemo и useCallback, но я не могу понять, как заставить его работать. Проблема проходитвниз функцию, чтобы обновить его родитель. Я не могу понять, как это сделать, не обновляя его каждый раз, когда обновляется форма.
Я не могу найти решение онлайн в любом месте. Может быть, я ищуНеправильно. Спасибо за любую помощь, которую вы можете предложить!
Решение
Использование ответа Андрей-Голубенко и этой статьи Реакция оптимизации с React.memo, useCallback и useReducer Мне удалось придумать это решение: https://codesandbox.io/s/myrjqrjm18
Обратите внимание, что журнал консоли показывает только повторную визуализацию измененных компонентов.