모든 코드는 git repository에서 확인 가능합니다.
3.2 componentDidUpdate 메서드
-
코드 5-34 usePrevious 커스텀 훅
import { useEffect, useRef } from 'react'; //POINT1 export default function(value) { //POINT2 const valueRef = useRef(); //POINT3 useEffect( () => { valueRef.current = value; }, [ value ] ); //POINT4 return valueRef.current || ''; }
-
⭐️ usePrevious 설명
- 코드 5-22 참고
- POINT 1. 매개변수로 현재 값을 받는다.
- POINT 2. 이전 값을 기억하기 위해 useRef 훅을 이용
- POINT 3. 렌더링 후 현재 값을 이전 값으로 만든다.
- POINT 4. 이전 값을 반환
-
⭐️ input에 입력시 수행 순서
- debugger 순서로 callstack순서를 확인해보자(step 1,2,3 확인)
- ⭐️ useState의 setxxx function이후 가 일어나면
setxxx functino이 있는 function 전체 다시 수행된다.
그리고
useEffect가 있다면 useEffect가 비동기로 수행된다.
-
-
코드 5-35 훅으로 변환할 componentDidUpdate 메서드
import React from 'react'; class Profile extends React.Component { state = { name: this.props.name }; componentDidUpdate(prevProps) { const { userId, name } = this.props; if (prevProps.userId !== userId) { this.setState({ name }); } } render() { return ( <div> ... </div> ); } } export default Profile;
-
코드 5-36 componentDidUpdate 메서드를 훅으로 변환하기
userIdd가 변경된 경우 name 상탯값을 새로운 사용자 이름으로 변경
- POINT1. userPrevious 훅을 이용해서 이전 userId를 저장
- POINT2. 마운트 여부를 useRef훅으로 관리
- POINT3. userIdd가 변경된 경우 name 상탯값을 새로운 사용자 이름으로 변경
import React, { useState, useEffect, useRef } from 'react'; import usePrevious from './customHook/usePrevious'; //props = {id name, age, date} export default function({ id, name, age, date }) { const [ userName, setUserName ] = useState(name); const [ userId, setUserId ] = useState(id); //POINT1 const prevUserId = usePrevious(userId); //POINT2 const isMountedRef = useRef(false); useEffect(() => { if (isMountedRef.current) { //POINT3 if (prevUserId !== userId) { setUserName(userName); } } else { isMountedRef.current = true; } }); const onClick = () => { setUserName('otherJyoon'); setUserId('okwoyjy'); }; return ( <div> <div> <h1> 예제 </h1> {(backtic)this is current userName: ${userName}(backtic)} <br /> <button onClick={onClick}>버튼으로 componentDidupdate 테스트 </button> </div> </div> ); }
-
코드 5-37 useOnUpdate 커스텀 훅
import { useRef, useEffect } from 'react'; export default function(func) { const isMountedRef = useRef(false); useEffect(() => { if (isMountedRef.current) { func(); } else { isMountedRef.current = true; } }); }
- 마운트가 됐을때 넘겨 받은 function을 수행해주는 훅
3.3 getDerivedStateFromProps 메서드
-
코드 5-38 훅으로 변경할 getDerivedStateFromProps 정적 메서드
import React from 'react'; class SpeedIndicator extends React.Component { state = { isFaster: false, prevSpeed: 0 }; static getDerivedStateFromProps(props, state) { if (props.speed !== state.prevSpeed) { return { isFaster: props.speed > state.prevSpeed, prevSpeed: props.speed }; } return null; } render() { const { isFaster, prevSpeed } = this.state; const { speed } = this.props; return ( <div> <p>current spped: {speed}</p> <p>getting faster?: {isFaster ? 'yes' : 'no'}</p> </div> ); } } class car extends React.Component { state = { speed: 0, enterSpeed: 0 }; handleChange = (e) => { console.log('### handleChange: '); this.setState({ speed: e.target.value }); }; handleSubmit = (e) => { console.log('### handleSubmit: '); const { speed } = this.state; debugger; this.setState({ enterSpeed: speed }); e.preventDefault(); }; render() { const { speed, enterSpeed } = this.state; return ( <div> 이건차다 스피드 입력해봐 <form onSubmit={this.handleSubmit.bind(this)}> <input type='text' value={speed} onChange={this.handleChange.bind(this)} /> <br /> <button type='submit'>enter</button> </form> <br /> <SpeedIndicator speed={enterSpeed} /> </div> ); } } export default car;
-
코드 5-39 getDerivedStateFromProps 정적 메서드를 훅으로 변경하기
import React, { useState, useEffect } from "react"; function SpeedIndicator({ speed }) { //POINT1 const [isFaster, setIsFaster] = useState(false); const [prevSpeed, setPrevSpeed] = useState(0); if (speed !== prevSpeed) { setIsFaster(speed > prevSpeed); setPrevSpeed(speed); } return <p>gettin faster?: {isFaster ? "yes" : "no"}</p>; } export default SpeedIndicator;
- speed 속성값이 변경되면 렌더링 과정에서 바로 상탯값을 변경
- 리액트는 렌더 함수에서 상탯값을 변경하면 변경된 상탯값으로 렌더 함수를 다시 호출 한다.
- getDerivedStateFromProps 정적 메서드를 사용한 방법 보다는 조금비효율 적인 측면이 있지만 돔을 변경하기 전에 발생하는 연산이므로 성능에 크게 영향을 주지 않는다.
-
주의
- 렌더 함수가 무한대로 호출될 수 있다.
- 코드5-39에서 작성한 prevSpeed를 useState훅으로 관리하지 않고 이전에 작성한 usePreviou 커스터 훅으로 관리했다면 렌더함수가 무한대로 호출된다.
3.4 forceUpdate 메서드
-
코드 5-40 useReducer 훅을 이용해서 forceUpdate 메서드를 구현하기
import React, { useReducer } from 'react'; function MyComponent() { //POINT1 const [ _, forceUpdate ] = useReducer((s) => s + 1, 0); function onClick() { forceUpdate(); } }
- forceUpdate 메서드의 사용은 지양해야 하지만 필요한 경우 훅으로 구현할 수 있다.
- POINT1. forceUpdate 함수를 호출하면 상탯값이 항상 변경되므로 클래스형 컴포넌트의 forceUpdate 메서드 처럼 동작한다.