ㅇㅇㅈ Blog

프론트엔드 수행중

0%

react-side-effect

useEffect

1
2
3
React.useEffect(()=>{}, [deps])
// function : 수행하고자 하는 작업
// deps : 배열 형태이며 배열 안에는 감시하고자 하는 특정 값 or 빈 배열
  • 배열을 생략하면 렌더링이 발생할때 마다 실행된다
  • 컴포넌트가 화면에 가장 처음 렌더링 될때 한번만 실행하고 싶을 떄는 deps 위치에 빈 배열을 넣는다
  • 배열안에 값이 있으면 특정 값이 바뀔때만 실행된다

https://ko.reactjs.org/docs/hooks-effect.html#effects-without-cleanup

useEffect Hook을 componentDidMount와 componentDidUpdate, componentWillUnmount가 합쳐진 것으로 생각해도 좋습니다.

1
2
3
4
5
6
7
8
9
10
11
React.useEffect(()=>{
console.log('렌더링 될때마다 실행')
})

React.useEffect(()=>{
console.log('마운트 될 때만 실행된다')
}, [])

React.useEffect(()=>{
console.log('state가 변경 될때만 실행된다')
}, [state,state])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
const root = document.querySelector('#root')

function Child() {
console.log(' Child render start')
const [text, setText] = React.useState(() => {
console.log(' Child useState')
return 'Hi'
})
React.useEffect(() => {
console.log(' Child useEffect no deps')
return () => {
console.log(' Child CleanUp no deps')
}
})
React.useEffect(() => {
console.log(' Child useEffect empty deps')
return () => {
console.log(' Child CleanUp empty deps')
}
}, [])
React.useEffect(() => {
console.log(' Child useEffect [text] deps')
return () => {
console.log(' Child CleanUp [text] deps')
}
}, [text])
function changeHandler(e) {
setText((cur) => {
return cur = e.target.value
})
}
const element = (
<>
<input onChange={changeHandler}></input>
<p>{text}</p>
</>
)
console.log(' Child render end')
return element
}
const App = () => {
console.log('App render start ')
const [show, setShow] = React.useState(() => {
console.log("App useState")
return false
})
React.useEffect(() => {
console.log("App uesEffect, [show] deps")
return () => {
console.log("App CleanUp, [show] deps")
}
}, [show])
React.useEffect(() => {
console.log("App uesEffect, empty deps")
return () => {
console.log("App CleanUp, empty deps")
}
}, [])
React.useEffect(() => {
console.log("App uesEffect, no deps")
return () => {
console.log("App CleanUp, no deps")
}
})
function handleClick() {
setShow(cur => !cur)
}
console.log('App render end ')
return (
<>
<button onClick={handleClick}>search</button>
{show ? (
<Child />
) : null}

</>
)
}
ReactDOM.render(<App />, root)

콘솔로 hook의 호출 시점을 찍어본다

1. 첫 렌더시

1. App이 렌더
2. useState 실행 
3. 렌더종료 후에 useEffect가 호출된다

2. App 컴포넌트에 변경이 생겼을때

1. App 렌더 후에 렌더 종료
2. Child 컴포넌트 렌더 시작
3. Child의 useState 호출
4. Child 렌더 종료
5. 후에 App의 useEffect CleanUp 이 호출됨 이때 빈 배열[] 이 들어간 useEffect는 실행 되지 않는다.
6. Child의 useEffect 호출
7. 마지막에 App의 useEffect가 호출된다 이때도 빈 배열[] useEffect는 호출 안됨.

3. Child 컴포넌트에 변경이 생겼을때

1. Child 렌더 시작
2. Child 렌더 종료
3. Child useEffect cleanup 호출 빈배열은 호출 안됨
4. Child useEffect 호출 빈배열 호출 안됨

4. 이후 App 컴포넌트에 다시 변경이 생겼을때

1. App 렌더 시작
2. App 렌더 종료
3. Child useEffect cleanup 호출 > 전부 호출 된다
4. App useEffect cleanup 호출 > 빈 배열 호출 안됨
5. App useEffect 호출 > 빈 배열 호출 안됨

Custom hook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
function Btn() {
const [keyword, setKeyword] = React.useState("")
const [typing, setTyping] = React.useState(false)
const [result, setResult] = React.useState("")

React.useEffect(() => {
console.log('effect')
window.localStorage.setItem("keyword", keyword)
}, [keyword])
React.useEffect(() => {
console.log('effect')
window.localStorage.setItem("keyword", keyword)
}, [result])

function handleChange(e) {
setKeyword((cur) => cur = e.target.value)
setTyping(true)
}
function handleClick() {
setTyping(false)
setResult((cur) => cur = `We find result of ${keyword}`)
}
return (
<>
<input type="text" onChange={handleChange} value={keyword}></input>
<button onClick={handleClick}>search</button>
<p>{typing ? `Looking for ...${keyword}` : result}</p>
</>
)
}
const App = () => {
return (
<Btn />
)
}
ReactDOM.render(<App />, root)
  • useEffect()의 하는 동작이 동일한데 코드가 반복된다
  • 함수처리로 묶어 줄 수 있다
  • 반복되는 훅 활용 메소드들을 하나로 줄여줌으로써 더 간결하고 보기 좋은 코드를 만들 수 있는 것이 바로 custom hook
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function Btn() {

function useLocalStorage(itemName, value = "") {
const [state, setState] = React.useState(() => {
return window.localStorage.getItem(itemName) || value
})
React.useEffect(() => {
window.localStorage.setItem(itemName, state)
}, [state])

return [state, setState]
}

const [keyword, setKeyword] = useLocalStorage("keyword")
const [typing, setTyping] = useLocalStorage("typing", false)
const [result, setResult] = useLocalStorage("result")


function handleChange(e) {
setKeyword((cur) => cur = e.target.value)
setTyping(true)
}
function handleClick() {
setTyping(false)
setResult((cur) => cur = `We find result of ${keyword}`)
}
return (
<>
<input type="text" onChange={handleChange} value={keyword}></input>
<button onClick={handleClick}>search</button>
<p>{typing ? `Looking for ...${keyword}` : result}</p>
</>
)
}
const App = () => {
return (
<Btn />
)
}
ReactDOM.render(<App />, root)