오늘은 ReactJS 스터디 여섯 번째 날입니다. 오늘도 화이탱구리구리!
when we change the state, the whole code renders again but with the new value
however, there are sometimes you don't want to call the whole function again (e.g., when you have an API to call and you have to call the API every time it renders) -> you want some codes in the component only runs one time but never again
import {useState} from "react";
function App() {
const [counter, setValue] = useState(0);
//counter is set to default and onclick it increments from the previous counter +1
const onClick = () => setValue((prev) => prev+1);
return (
<div><h1>{counter}</h1>
<button onClick={onClick}>click me</button>
</div>
);
}
export default App;
using useEffect to make sure the code only runs one time
import {useState, useEffect} from "react";
//useEffect takes two argument which is the code we want to run only once, and magical argument
function App() {
const [counter, setValue] = useState(0);
//counter is set to default and onclick it increments from the previous counter +1
const onClick = () => setValue((prev) => prev+1);
console.log("i run all the time");
const iRunOnlyOnce = () => {
console.log("i run only once");
};
useEffect(iRunOnlyOnce, []);
return (
<div>
<h1>{counter}</h1>
<button onClick={onClick}>click me</button>
</div>
);
}
export default App;
another way of writing the code
import {useState, useEffect} from "react";
//useEffect takes two argument which is the code we want to run only once, and the dependencies (it is what react.js needs to watch, and if they change react.js will run the code)
function App() {
const [counter, setValue] = useState(0);
//counter is set to default and onclick it increments from the previous counter +1
const onClick = () => setValue((prev) => prev+1);
console.log("i run all the time");
useEffect(()=> {
console.log("i run only once - call the api");
},[]);
return (
<div>
<h1>{counter}</h1>
<button onClick={onClick}>click me</button>
</div>
);
}
export default App;
search for the movie that the user wants only when the movie (the specific component) changes
import { useState, useEffect } from "react";
function App() {
const [counter, setValue] = useState(0);
const [keyword, setKeyword] = useState("");
const onClick = () => setValue((prev) => prev +1);
const onChange = (event) => setKeyword(event.target.value);
console.log("I run all the time");
useEffect(() => {
console.log("CALL THE API...");
}, []);
useEffect(() => {
if (keyword !== "" && keyword.length > 5) {
console.log("SEARCH FOR", keyword);
}
}, [keyword]);
return (
<div>
<input
value={keyword}
onChange={onChange}
type="text"
placeholder="Search here..."
/>
<h1>{counter}</h1>
<button onClick = {onClick}>click me</button>
</div>
);
};
export default App;
the output
making the change for only counter and for only keyword
import { useState, useEffect } from "react";
function App() {
const [counter, setValue] = useState(0);
//keyword is being modified by setKeyword function
const [keyword, setKeyword] = useState("");
const onClick = () => setValue((prev) => prev +1);
const onChange = (event) => setKeyword(event.target.value);
//will run only one time as we are not watching anybody in [] -> the second argument
useEffect(() => {
console.log("I run only once");
}, []);
//will run when keyword changes (of the second argument)
useEffect(() => {
console.log("I run when keyword changes");
}, [keyword]);
useEffect(() => {
console.log("I run when counter changes");
}, [counter]);
//run when either one of it changes (i.e., keyword or counter)
useEffect(() => {
console.log("I run when keyword & counter changes");
}, [keyword, counter]);
return (
<div>
<input
value={keyword}
onChange={onChange}
type="text"
placeholder="Search here..."
/>
<h1>{counter}</h1>
<button onClick = {onClick}>click me</button>
</div>
);
};
export default App;
the output
displaying and hiding certain component
import { useState, useEffect } from "react";
function Hello (){
useEffect (() => {
//when we show the component this function runs and shows the console.log line
console.log("I'm here!");
},[]);
return <h1>Hello</h1>;
}
function App() {
const [showing, setShowing] =useState(false);
//display the opposite of the previous state
const onClick = () => setShowing((prev)=>!prev);
return <div>
{showing ? <Hello /> : null}
<button onClick={onClick}>{showing ? "Hide":"Show"}</button>
</div>;
}
export default App;
know when the component was created and destroyed -> cleanup
cleanup is not used very often -> Code can be run even when a component is destroyed
import { useState, useEffect } from "react";
function Hello (){
useEffect (() => {
//allows you to know when the component was created and destroyed
console.log("created:)");
return () => console.log("destroyed :(");
},[]);
return <h1>Hello</h1>;
}
function App() {
const [showing, setShowing] =useState(false);
//display the opposite of the previous state
const onClick = () => setShowing((prev)=>!prev);
return <div>
{showing ? <Hello /> : null}
<button onClick={onClick}>{showing ? "Hide":"Show"}</button>
</div>;
}
export default App;
another example of using cleanup with using functions
import { useState, useEffect } from "react";
function Hello() {
function byeFn() {
console.log("bye :(");
}
function hiFn() {
//run the hiFn and return byeFn when the component is destroyed
console.log("created :)");
return byeFn;
}
useEffect(hiFn, []);
return <h1>Hello</h1>;
}
function App() {
const [showing, setShowing] =useState(false);
//display the opposite of the previous state
const onClick = () => setShowing((prev)=>!prev);
return <div>
{showing ? <Hello /> : null}
<button onClick={onClick}>{showing ? "Hide":"Show"}</button>
</div>;
}
export default App;
another way of writing the previous code with function inside of useEffect
import { useState, useEffect } from "react";
function Hello() {
useEffect(() => {
console.log("hi :)");
return () => {
console.log("bye :(");
}
}, []);
return <h1>Hello</h1>;
}
function App() {
const [showing, setShowing] =useState(false);
//display the opposite of the previous state
const onClick = () => setShowing((prev)=>!prev);
return <div>
{showing ? <Hello /> : null}
<button onClick={onClick}>{showing ? "Hide":"Show"}</button>
</div>;
}
export default App;
컴포넌트가 destroy될 때도 코드를 실행할 수 있다 -> return으로 함수를 만들어주면 됨
useEffect는 함수를 받고, 이 함수는 dependency가 변화할 때 호출됨
현재는 dependency가 비어있으니 컴포넌트가 처음 생성될 때 함수가 호출된 후 다시
호출 되지 않음
그래서 컴포넌트가 파괴될 때도 함수를 실행하고 싶으면
useEffect 함수가 새로운 함수를 return해야 함
-> 왜냐면 deps가 비어있으면 자동으로 컴포넌트가 파괴될 때 cleanup함수가 실행되는데 그 과정이 리렌더링으로 useEffect함수가 실행되고 클린업하면서 이전에 있던 이펙트인 console.log(“created :) )가 삭제되고 새로운 이펙트 함수인 return함수가 실행되기 때문이다.
리렌더링 -> 이전 이펙트 클린업 -> 이펙트 실행