<aside> 💡 상태는 왠만하면 사용할곳과 가장 가까운 곳에 위치해야한다 + 언제나 React.state가 필요할까?
</aside>
불필요한 리랜더링을 해결하고싶을 땐 상태를 사용하는 가장 가까운 곳에 두는것이 편하다.
아니, 최대한 상태를 사용하지 않는 것이 좋다.
[Form]
function SlowForm() {
// manage input field values
const [fieldValues, setFieldValues] = useReducer(
(state, action) => ({
...state,
...action,
}),
initialFieldValues,
);
// manage input field is focused
const [touchedFields, setTouchedFields] = useReducer(
(state, action) => ({
...state,
...action,
}),
initialTouchedFields,
);
const [wasSubmitted, setWasSubmitted] = useState(false);
// validate form & submit
function handleSubmit(event) {
event.preventDefault();
const formIsValid = fieldNames.every(name => !getFieldError(fieldValues[name]));
setWasSubmitted(true);
if (formIsValid) {
console.log(`Slow Form Submitted`, fieldValues);
};
};
// change input value
function handleChange(event) {
setFieldValues({ [event.currentTarget.name]: event.currentTarget.value });
};
// check input on Blur
function handleBlur(event) {
setTouchedFields({ [event.currentTarget.name]: true });
};
return (
<form noValidate onSubmit={handleSubmit}>
{fieldNames.map(name => (
<SlowInput
key={name}
name={name}
fieldValues={fieldValues}
touchedFields={touchedFields}
wasSubmitted={wasSubmitted}
handleChange={handleChange}
handleBlur={handleBlur} />
))}
<button type="submit">Submit</button>
</form>
)
}
위 방식은 Form Component
에서 모든 input field
를 관리하는 방식이다.
적어도 내가 지금까지 본 많은 Form component
들이 위와같은 방식으로 되어있는데,
이 방식은 한가지 큰 단점이 있다.
바로 모든 유저의 interaction
하나하나에 Form
전체의 리랜더링이 일어난다는 것인데,
Memoization
도 위 문제를 근본적으로 해결할 수 없다.
왜냐면 props
로 넘기는 fieldValues
자체가 유저의 타이핑 하나하나에 반응하여 리랜더링 되기 때문이다.
만약 Form
이 심플하다면 큰문제는 없다. 리액트에서 리랜더링은 당연한 현상이고,
작은 리소스를 리랜더링 하는 행위는 유저에게 유의미한 불편하기 주기 힘들것이기 때문이다.
하지만 우리의 Form
은 아래와 같은 이유로 쉽게 복잡해질 수 있다.