hook flow - component를 그리고 hook을 사용하였는데 그 hook이 언제 불리고 언제 사라지고 중첩적으로 comp 만들었을때는 comp간 hook의 호출 타이밍은 언제인지?
<script type="text/babel">
const rootElement = document.getElementById("root");
const App = () => {
console.log("APP render start");
const [show, setShow] = React.useState(() => {
//lazy initialize
console.log("APP useState call");
return false;
});
React.useEffect(() => {
console.log("APP useEffect, no deps");
});
React.useEffect(() => {
console.log("APP useEffect, empty deps");
}, []);
React.useEffect(() => {
console.log("APP useEffect, [show] deps");
}, [show]);
function handleClick() {
//set함수는 인자로 이전값이 들어온다.
//setState의 처번째 함수는 이전값이다.
setShow((prev) => !prev);
}
const InputBox = () => {
return (
<>
{" "}
<input />
<p></p>
</>
);
};
console.log("APP render end");
return (
<>
<button onClick={handleClick}>search</button>
{show && <InputBox />}
</>
);
};
ReactDOM.render(<App />, rootElement);
</script>
호출 순서
APP render start -> useState -> APP render end -> useEffect(선언 순서로 호출됨)
-> button click ->
APP render start -> APP render end -> useEffect([] 제외)
중요한것 ! render가 끝난다음에 useEffect가 동작한다.
이유는 ??? 사이드 이펙트이기 때문에 일단 다 그려지고 난 뒤 이펙트들에 의한 동작들에 대한 이펙트를 발생시킨다.
code tip
setState 함수는 첫번째 인자로 이전 state의 값을 가지고 있다.
<script type="text/babel">
const rootElement = document.getElementById("root");
const Child = () => {
console.log("Child render start");
const element = (
<>
{" "}
<input />
<p></p>
</>
);
console.log("Child render end");
return element;
};
const App = () => {
console.log("APP render start");
const [show, setShow] = React.useState(() => {
//lazy initialize
console.log("APP useState call");
return false;
});
React.useEffect(() => {
console.log("APP useEffect, no deps");
});
React.useEffect(() => {
console.log("APP useEffect, empty deps");
}, []);
React.useEffect(() => {
console.log("APP useEffect, [show] deps");
}, [show]);
function handleClick() {
//set함수는 인자로 이전값이 들어온다.
//setState의 처번째 함수는 이전값이다.
setShow((prev) => !prev);
}
console.log("APP render end");
return (
<>
<button onClick={handleClick}>search</button>
{show ? <Child /> : null}
</>
);
};
ReactDOM.render(<App />, rootElement);
</script>
호출 순서
APP render start -> useState -> APP render end -> useEffect(선언 순서로 호출됨)
-> button click ->
APP render start -> APP render end ->
-> Child render start -> Child render end -> useEffect([] 제외)
<script type="text/babel">
const rootElement = document.getElementById("root");
const Child = () => {
console.log(" Child render start");
const [text, setText] = React.useState(() => {
console.log(" Child useState");
return "";
});
React.useEffect(() => {
console.log(" Child useEffect, no deps");
});
React.useEffect(() => {
console.log(" Child useEffect, empty deps");
}, []);
React.useEffect(() => {
console.log(" Child useEffect, [text] deps");
}, [text]);
const handleChange = (e) => {
setText(e.target.value);
};
const element = (
<>
{" "}
<input onChange={handleChange} />
<p>{text}</p>
</>
);
console.log(" Child render end");
return element;
};
const App = () => {
console.log("APP render start");
const [show, setShow] = React.useState(() => {
//lazy initialize
console.log("APP useState call");
return false;
});
React.useEffect(() => {
console.log("APP useEffect, no deps");
});
React.useEffect(() => {
console.log("APP useEffect, empty deps");
}, []);
React.useEffect(() => {
console.log("APP useEffect, [show] deps");
}, [show]);
function handleClick() {
//set함수는 인자로 이전값이 들어온다.
//setState의 처번째 함수는 이전값이다.
setShow((prev) => !prev);
}
console.log("APP render end");
return (
<>
<button onClick={handleClick}>search</button>
{show ? <Child /> : null}
</>
);
};
ReactDOM.render(<App />, rootElement);
</script>
호출 순서
부모가 다 그려지고 -> 자식 clidren 다 그려짐 -> 자식 side effect -> 부모 side effect -> button click -> 부모 그려지고 -> 부모 side effect
useEffect의 함수안에서 return 하면서 어떤 함수를 호출하게 되면
이 함수의 side effect가 setup되어 있는 것을 지우고 다시 생성한다.
<script type="text/babel">
const rootElement = document.getElementById("root");
const Child = () => {
console.log(" Child render start");
const [text, setText] = React.useState(() => {
console.log(" Child useState");
return "";
});
React.useEffect(() => {
console.log(" Child useEffect, no deps");
return () => {
console.log(" Child useEffect,[Clean up] no deps");
};
});
React.useEffect(() => {
console.log(" Child useEffect, empty deps");
return () => {
console.log(" Child useEffect,[Clean up] empty deps");
};
}, []);
React.useEffect(() => {
console.log(" Child useEffect, [text] deps");
return () => {
console.log(" Child useEffect,[Clean up] [text] deps");
};
}, [text]);
const handleChange = (e) => {
setText(e.target.value);
};
const element = (
<>
{" "}
<input onChange={handleChange} />
<p>{text}</p>
</>
);
console.log(" Child render end");
return element;
};
const App = () => {
console.log("APP render start");
const [show, setShow] = React.useState(() => {
//lazy initialize
console.log("APP useState call");
return false;
});
React.useEffect(() => {
console.log("APP useEffect, no deps");
return () => {
console.log("APP useEffect,[Clean up] no deps");
};
});
React.useEffect(() => {
console.log("APP useEffect, empty deps");
return () => {
console.log("APP useEffect,[Clean up] empty deps");
};
}, []);
React.useEffect(() => {
console.log("APP useEffect, [show] deps");
return () => {
console.log("APP useEffect,[Clean up] [show] deps");
};
}, [show]);
function handleClick() {
//set함수는 인자로 이전값이 들어온다.
//setState의 처번째 함수는 이전값이다.
setShow((prev) => !prev);
}
console.log("APP render end");
return (
<>
<button onClick={handleClick}>search</button>
{show ? <Child /> : null}
</>
);
};
ReactDOM.render(<App />, rootElement);
</script>
호출 순서
부모가 다 그려지고 -> 자식 다 그려짐 -> 부모 side effect CleanUp -> 자식 side effect start-> 부모 side effect start -> text 입력 -> 자식 다 그려짐 -> 자식 side effect CleanUp -> 자식 side effect start -> button click -> 부모 그려지고 -> 자식 side effect CleanUp -> 부모 side effect CleanUp -> 부모 side effect start
useEffect는 어떤 변경에 따라서 실행이 되는데 실행이 되기전에 CleanUp이 먼저 일어나는 것이다.
Child component가 unMount(사라질 때) CleanUp은 다이루어 진다.
정리
- useEffect -> render가 끝난뒤 호출
- update시 -> useEffect clean up 먼저, useEffect
- ( 처음 생성시에는 cleanUp 먼저 호출 안함 useEffect만 호출 한 번이라도 useEffect가 등록 되어 있으면 cleanUp하고 useEffect에 update된 내용을 반영한다. 불변의 상황을 계속 만들려고하는 것 -> 있던 것을 지우고 새로운것을 다시 갈아끼우는)
- dependency array -> 전달받은 값의 변화 있는 경우에만