본문 바로가기

Web/React & Next.js

Hooks

useState: 가장 기본적인 hook로 함수 컴포넌트에서도 가변적인 상태를 지닐 수 있게한다.

import { useState } 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 onInsert = e =>{
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber('');
    };

    return(
        <div>
            <div>
                <input name="name" value={number} onChange={onChange}/>
                <button onClick={onInsert}>등록</button>
            </div>
            <ul>
                {list.map((value,index) => (
                    <li key={index}>{value}</li>
                ))}
            </ul>
            <div>
                <b>평균값:</b>{getAverage(list)}
            </div>
        </div>
    );
}

export default Average;

input 내용이 바뀔 때 마다 getAverage가 호출된다

 

useEffect: 리액트 컴포넌트가 랜더링 될 때마다 특정 작업을 수행하도록 설정할 수 있게한다

(componentDidMount+componentDidUpdate 형태)

import { useState, useEffect } from 'react';

const Info = () =>{
    const [name, setName] = useState('');
    const [nickname ,setNickName] = useState('');

    useEffect (() => {
        console.log('렌더링 완료됬습니다');
        console.log({
            name, nickname
        });
        //console.log('마운트 될 때만 실행');
    });

    const onChangeName = e =>{
        setName(e.target.value);
    };

    const onChangeNickName = e =>{
        setNickName(e.target.value);
    };

    return(
        <div>
            <div>
                <input value={name} onChange={onChangeName}/>
                <input value={nickname} onChange={onChangeNickName}/>
            </div>
            <div>
                <b>이름:</b>{name}
                <b>닉네임:</b>{nickname}
            </div>
        </div>
    );
};

export default Info;
useEffect (() => {
        //console.log('렌더링 완료됬습니다');
        //console.log({
            //name, nickname
        //});
        console.log('마운트 될 때만 실행');
    }, []);

useEffect을 이렇게 바꾸면 마운트 될 때만 console에 찍힌다

useEffect (() => {
        //console.log('렌더링 완료됬습니다');
        //console.log({
            //name, nickname
        //});
        console.log(name);
    }, [name]);

name 업데이트 될 때만 실행

 useEffect (() => {
        //console.log('렌더링 완료됬습니다');
        //console.log({
            //name, nickname
        //});
        console.log('effect');
        return () =>{
            console.log('cleanup');
            console.log(name);
        };
    }, [name]);
import { useState } from 'react';

const App = () =>{
  const [visible, setVisible] = useState(false);
  return(
    <div>
      <button 
        onClick={() => 
          {setVisible(!visible)}
        }
      >
        {visible ? '숨기기': '보이기'}
      </button>
      <hr/>
      {visible && <Info/>}
    </div>
  );

숨길때 name과 nickName이 초기화되며 그 전에 데이터가 콘솔에 나타난다

 

useReducer: 다양한 컴포넌트 상황에 따라 다양한 상태를 다른 값으로 업데이트해 주고 싶을 때 사용

                 현재 상태, 업데이트를 위해 필요한 정보를 담은 액션 값을 전달받아 새로운 상태를 반환하는 함수

import { useReducer } from 'react';

function render(state, action){
    switch (action.type){
        case 'INCREMENT':
         return { value: state.value +1 };
        case 'DECRMENT':
         return { value: state.value -1 };
        default:

        return state;
    }
}

const Counter2 =() =>{
    const [state, disPatch]= useReducer(render, {value:0});

    return(
        <div>
            <p>
                현재 카운터 값은 <b>{state.value}</b>
            </p>
            <button onClick={()=> disPatch({ type: 'INCREMENT'})}>+1</button>
            <button onClick={()=> disPatch({ type: 'DECRMENT'})}>-1</button>
        </div>
    );
};

export default Counter2;
import { useReducer } from 'react';

function render(state, action){
    return{
       ...state,
       [action.name]: action.value
    };
}

const Info2 =() =>{
    const [state, disPatch]= useReducer(render, {name:'', nickName:''});
    const {name, nickName} =state;
    const onChange = e => {
        disPatch(e.target);
    };

    return(
        <div>
        <div>
            <input name="name" value={name} onChange={onChange}/>
            <input name="nickName" value={nickName} onChange={onChange}/>
        </div>
        <div>
            <b>이름:</b>{name}
            <b>닉네임:</b>{nickName}
        </div>
    </div>
    );
};

export default Info2;

useMemo: 함수 컴포넌트 내부에서 발생하는 연산을 최적화할 수 있다

import { 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 onInsert = e =>{
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber('');
    };

    const avg = useMemo(()=> getAverage(list), [list]);

    return(
        <div>
            <div>
                <input name="name" value={number} onChange={onChange}/>
                <button onClick={onInsert}>등록</button>
            </div>
            <ul>
                {list.map((value,index) => (
                    <li key={index}>{value}</li>
                ))}
            </ul>
            <div>
                <b>평균값:</b>{avg}
            </div>
        </div>
    );
}

export default Average;

list 배열의 내용이 바뀔 때만 getAverage 함수가 호출된다

 

useCallback: 렌더링 성능을 최적화 할 때 사용

import { useState, useMemo, useCallback } 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 = useCallback(e =>{
        setNumber(e.target.value);
    }, []);

    const onInsert = useCallback(e =>{
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber('');
    }, [number,list]);

    const avg = useMemo(()=> getAverage(list), [list]);

    return(
        <div>
            <div>
                <input name="name" value={number} onChange={onChange}/>
                <button onClick={onInsert}>등록</button>
            </div>
            <ul>
                {list.map((value,index) => (
                    <li key={index}>{value}</li>
                ))}
            </ul>
            <div>
                <b>평균값:</b>{avg}
            </div>
        </div>
    );
}

export default Average;

첫 렌더에만 함수 생성, number와 list가 바꼈을 때만 함수 생성

 

useRef: ref를 쉽게 사용할 수 있도록 한다

import { useState, useMemo, useCallback, useRef } 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 inputEI =useRef(null);

    const onChange = useCallback(e =>{
        setNumber(e.target.value);
    }, []);

    const onInsert = useCallback(e =>{
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber('');
        inputEI.current.focus();
    }, [number,list]);

    const avg = useMemo(()=> getAverage(list), [list]);

    return(
        <div>
            <div>
                <input name="name" value={number} onChange={onChange}/>
                <button onClick={onInsert}>등록</button>
            </div>
            <ul>
                {list.map((value,index) => (
                    <li key={index}>{value}</li>
                ))}
            </ul>
            <div>
                <b>평균값:</b>{avg}
            </div>
        </div>
    );
}

export default Average;

current값이 실제 엘리먼트를 가리킴

ref 안에 값이 바뀌어도 렌더링 되지 않는다

 

커스텀 Hooks 만들기

import { useReducer } from 'react';

function Reducer(state, action){
    return{
        ...state,
        [action.name]: action.value
    };
}

export default function useInputs(initialForm){
    const [state,disPatch]= useReducer(Reducer, initialForm);
    const onChange = e =>{
        disPatch(e.target);
    };

    return [state, onChange];
}
//import { useReducer } from 'react';
import useInput from "./useInput";

const Info2 =() =>{
    const [state, onChange]= useInput({name:'', nickName:''});
    const {name, nickName} =state;

    return(
        <div>
        <div>
            <input name="name" value={name} onChange={onChange}/>
            <input name="nickName" value={nickName} onChange={onChange}/>
        </div>
        <div>
            <b>이름:</b>{name}
            <b>닉네임:</b>{nickName}
        </div>
    </div>
    );
};

export default Info2;

'Web > React & Next.js' 카테고리의 다른 글

react 아이콘 넣기  (0) 2022.04.12
컴포넌트 스타일링  (0) 2022.04.06
컴포넌트의 라이프사이클 메서드  (0) 2022.04.05
컴포넌트 반복  (0) 2022.04.04
DOM에 이름 달기  (0) 2022.04.03