January 08, 2020
리액트 구버전에서는 클래스 컴포넌트에서만! state 관리랑 라이프사이클 등을 사용할 수 있었음. 그런데 버전이 업데이트 되면서 함수형 컴포넌트에서도 기능들을 사용할 수 있게 만들어줌. 그것이 바로 Hooks! useState
, useEffect
등등등 여러가지…
말 그대로 state 관리를 use한다는 거임. 첫번째 인자로 초깃값을 설정한 뒤에, 두번째 인자인 setter함수를 통해 변경할 state를 설정하면 됨. 인자의 변수?값은 아무렇게나 설정해도됨 message든, setText, setColor 든 자기 맘대로 설정 가능쓰. 대신 setState
처럼 반드시 setter함수를 통해서만 state값을 설정해야함.
import React, { useState } from 'react';
const Say = () => {
const [message, setMessasge ] = useState(''); // 첫번째 인자는 초깃값, 두번쨰 인자는 setter함수
const onClickEnter = () => setMessasge("클릭미클릭미");
const onClickLeave = () => setMessage("클릭ㄴㄴㄴ");
return(
<div>
<button onClick={onClickEnter()}>입장<button/>
<button onClick={onClickLeave()}>퇴장<button/>
<h1>{message}</h1>
</div>
)
}
setter함수를 통해서 state값을 변경하는 것은 좋은데 만약 객체나 배열을 업데이트 해야할 경우에는 전개연산자라는 것을 통해서 사본을 만들어두고 사본을 setter함수를 통해 업데이트 하는 방식을 사용해야함. 한다리 건너 한다리 식으로 해야한단 뜻임.
예시
const obj = { a: 1, b: 2 }
const nextObj = { ...obj, b: 3 } // ...연산자를 통해 obj 객체를 전개한 뒤, b를 3으로 업데이트 하는 것.
컴포넌트가 렌더링될 때마다 어떤 작업을 수행함. 렌더링+업데이트를 합친 격인데 필요에 따라 선택해서 사용 가능.
// Info.js
import React, { useState, useEffect } from 'react'
const Info = () => {
const [name, setName] = useState('')
const [nickname, setNickname] = useState('')
useEffect(() => {
console.log('렌더링이 완료되었습니다')
console.log(name + ',' + nickname)
})
const onChangeName = e => {
setName(e.target.value)
console.log('이름 바뀜??????????????')
}
const onChangeNickname = e => {
setNickname(e.target.value)
}
return (
<div>
<input onChange={onChangeName} />
<input onChange={onChangeNickname} />
<h1>
{name},{nickname}
</h1>
</div>
)
}
export default Info
이름과 닉네임을 적을 때마다 콘솔창에 기입됨. 만약 업데이트 시에만 실행하고 싶다면 두번째 매개변수로 업데이트 관리하고 싶은 값을 적어줌
useEffect(() => {
console.log('업데이트가 하고 싶니?')
console.log(name)
}, [name])
또한 컴포넌트가 마운트될 때만 사용하고 싶다면 두번째 매개변수로 빈 값을 넣어주면 됨
useEffect(() => {
console.log("마운트만 가능함"));
}, [])
컴포넌트에 변화가 있기 전에 어떤 작업을 수행하고 싶다면, cleanup
이라는 뒷정리함수를 return.
// Info.js
useEffect(() => {
console.log('effect')
console.log(name)
return () => {
console.log('cleanup')
console.log(name)
}
})
// App.js
import React, { useState } from 'react'
import Info from './Info'
const App = () => {
const [visible, setVisible] = useState(false)
return (
<div>
<button
onClick={() => {
setVisible(!visible)
}}
>
{visible ? '숨김' : '보임'}
</button>
<hr />
{visible && <Info />}
</div>
)
}
export default App
컴포넌트 내부의 연산을 최적화 시킴. 특정 값이 바뀌었을 때만 연산을 실행하고 그게 아니라면 이미 연산한 결과를 다시 사용하는 식으로 효울적으로 연산할 수 있음.
import React, { useState, useMemo } from 'react'
const getAverage = numbers => {
console.log('평균값 계산중')
if (numbers.length === 0) return 0
const sum = numbers.reduce((a, b) => a + b)
return sum / numbers.length
}
const Average = () => {
const [list, setList] = useState([])
const [number, setNumber] = useState('')
const onChange = e => {
setNumber(e.target.value)
}
const onSubmit = e => {
const nextList = list.concat(parseInt(number))
setList(nextList)
setNumber('')
}
const avg = useMemo(() => getAverage(list), [list])
return (
<div>
<input value={number} onChange={onChange} />
<button onClick={onSubmit}>등록</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
<div>
<b>평균값 :{avg}</b>
</div>
</div>
)
}
export default Average
input이 onChange될 때마다 숫자값도 변하니 계속 렌더링 => 평균값을 구하는 함수도 계속 실행됨.
이걸 방지하기 위해 useMemo
를 사용하는 것임.
const avg = useMemo(() => getAverage(list), [list]);
이 한 줄 넣으면 화면에 출력되는 숫자 리스트가 바뀔 때만 렌더링 되면서 연산을 최적화 시킴.