
리액트의 데이터 흐름은 단방향입니다.
즉, 부모에서 자식으로만 전달이 가능하다는 거죠.
setState 는 비동기로 작동합니다.
why? setState가 동기로 작동하게 되면 변경될때마다 바로 바로 렌더링 하기 때문에 비효율적입니다.
값이 바뀔때마다 화면을 다시 그리게 되는 반복적인 방식은 비효율적일 수 밖에 없습니다.
따라서 임시 저장소에 모아두었다가 코드를 끝까지 읽고 한번에 바꿔서 렌더링합니다.
주어진 값들이 존재할 경우에만, active 되게 하는 예시
const [writer, setWriter] = useState('');
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
const [isActive, setIsActive] = useState(false);
const onChangeContent = (e) => {
setContent(e.target.value); //1번
if(writer && title && e.target.value) return setIsActive(true); // early-exit 패턴
setIsActive(false);
}; //2번
-> 간단히 설명하자면, 1번에서는 "이러한 작업을 수행하라!"는 명령만 내려진 상태입니다. 즉, 이 시점에서는 렌더링 전이며, 1번에서 content는 아직 빈 문자열입니다. 함수가 끝나는 2번 지점까지 실행된 후에야 렌더링이 이루어지고, 그제야 화면에 반영되는 것입니다.
해당 코드에서
if(writer && title && content)대신if(writer && title && e.target.value)로 조건을 확인하는 이유는setContent(e.target.value)가 비동기로 상태를 업데이트하기 때문입니다. 즉,setContent는 즉시content상태를 업데이트하지 않기 때문에,setContent호출 후에도content는 여전히 이전 값을 참조하고 있을 수 있습니다. 이로 인해if(writer && title && content)를 사용하면, 최신content값을 반영하지 못하고,if문이 기대한 대로 동작하지 않을 수 있습니다. 이를 방지하기 위해,content대신 직접 입력된 값인e.target.value를 사용하여 조건을 확인하는 것입니다.
아래의 버튼을 클릭하면 어떤 값이 도출되는지?
export default function stateTest(){
const [value,setValue]=useState(0)
const onClick = () => {
setValue(value+1)
setValue(value+1)
setValue(value+1)
}
return (
<div className="App">
<button onClick={onClick}>+</button>
<h1>{value}</h1>
</div>);
}
1 입니다.setState를 호출하면, 리액트는 이전 상태와 새로운 상태를 비교하기 시작합니다.setState를 여러 번 호출하더라도 성능을 최적화하기 위해 한 번에 배치(batch)하여 업데이트합니다.setState를 호출한 직후의 상태 값은 바로 반영되지 않을 수 있습니다.📌 리렌더가 되는 상황
1. 새로운 props가 들어올 때
2. 부모 컴포넌트가 렌더링 될 때
3. 강제 업데이트(forceUpdate)가 실행될 때
4. state가 변경될 때
++ 지식 하나 더 !
props drillingprops가 자식에게 넘겨주는 단계가 두단계 이상이 될 경우를 props drilling이 일어났다고 합니다. 이는 과도라지 않으면 괜찮지만, 과도하게 이루어질 경우 해당 props가 어디서 내려지고 있는지 찾는 것이 굉장히 난해해집니다.
따라서 최대한 drilling가 일어나지 않게 해주는 것이 코드의 가독성과 유지보수 측면에서는 유리합니다. -> 방지를 위해선 global state를 이용하는 것이 좋습니다.