CS/프로그래밍

리액트 Hook

밍지☆ 2024. 1. 2. 15:16

▶ hook이란?

리액트 v16.8에 새로 도입된 기능으로 함수 컴포넌트에서도 상태 관리를 할 수 있는 useState, 렌더링 직후 작업을 설정하는 useEffect 등의 기능을 제공하여 React state와 생명주기기능을 연동할 수 있게 해주는 함수

- 종류: useState, useEffect,useReducer,useMemo,useCallback,useRef, 커스텀

 

1)useState: 함수형 컴포넌트에서 상태관리를 해주는 훅

<Counter.js>

import  React,{useState} from 'react';



const Counter=()=>{

const [value,setValue]= useState(0);



return (

<div>

<p> 현재 카운터 값은 <b>{value}</b>입니다. </p>

<button onClick={{()=>setValue(value+1)}>+1</button>

<button onClick= {{()=>setValue(value-1)}>-1</button>

</div>

);

};

export default Counter

 

● useState 정리

- import 구문을 통해 불러옴. 

- useState 함수의 파라미터: 상태의 기본값 적음. 

ex) 현재 예제의 기본값: 0으로 설정

- useState 호출 시 배열 반환: 첫번째 원소- 상태 값, 두번째 원소- 상태 설정 값

- 상태 값을 업데이트, 즉 변화시킴.

- 하나의 useState 함수 - 하나의 상태값만 관리

 

 

2)useEffect:  리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 훅

<Info.js>

import {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);

};

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}

  </div>

  <div>

   <b> 닉네임:</b>{nickname}

  </div>

 </div>

</div>

);

};

export default Info;

 

● useEffect 정리

- import 구문으로 불러옴.

- 렌더링 되고 난 직후마다 실행, 두번째 파라미터 배열에 따라 실행조건 다름

1)업데이트될 때 실행시키지 않는 방법: 함수의 두번째 파라미터로 비어있는 배열을 넣어주기

  ex) useEffect(()=>{

  console.log('마운트 될 때만 실행됩니다!');

  },[]);

2) 특정 값이 변경될 때만 호출하고 싶은 경우: 두번째 파라미터로 전달되는 배열 안에 검사하고 싶은 값을 넣어주기

ex) useEffect(()=>{

  console.log('마운트 될 때만 실행됩니다!');

  },[name]);

*배열 안: useState를 통해 관리하고 있는 상태 or props로 전달받은 값 모두 상관없음!

- 컴포넌트가 언마운트되기 전 or 업데이트 되기 직전 수행: cleanup 함수 반환하기

  ex)

<Info.js>

 useEffect(()=>{

  console.log('effect');

  console.log(name)

  return ()=>{

  console.log('cleanup');

  console.log(name);

 }

  },[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>

<br/>

{visible&&<Info/>}

</div>

);

};

export default App;

//컴포넌트가 나타날때: 콘솔- effect, 사라질 때: 콘솔-cleanup

//렌더링될 때마다 뒷정리 함수가 계속 나타남, 뒷정리 함수가 호출될 때 업데이트되기 직전 값 보여줌

- 언마운트 될때만 뒷정리 함수 호출하고 싶다면: useEffecrt 함수의 두번째 파라미터에 비어있는 배열 넣기

 

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

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

<Counter.js>

import  React,{useReducer} from 'react';



function reducer(state,action){
//action.type에 따라 다른 작업 수행

switch (action.type){

case 'INCREMENT':

return {value:state.value +1};

case 'DECREMENT':

return {value:state.value -1};

default:

return state

 }

}

const Counter=()=>{

const [state,dispatch]= useReducer(reducer,{value:0});



return (

<div>

<p> 현재 카운터 값은 <b>{state.value}</b>입니다. </p>

<button onClick={()=>dispatch({type:'INCREMENT'})}>+1</button>

<button onClick= {{()=> dispatch({type:'DECREMENT'}) }>-1</button>

</div>

);

};

export default Counter

 

● useReducer 정리

- import 구문으로 불러옴.

- 첫번째 파라미터: 리듀서 함수, 두번째 파라미터: 해당 리듀서의 기본 값

- state: 현재 가리키고 있는 상태 dispatch: action을 발생시키는 함수

dispatch(action)과 같은 형태로, 함수 안에 파라미터로 액션 값을 넣어주면 리듀서 함수가 호출되는 구조

- 장점: 컴포넌트 업데이트 로직을 컴포넌트 바깥으로 빼낼 수 있음.

- 인풋 개수가 많아져도 코드를 깔끔하게 유지관리 가능

<Info.js>

<Info.js>

import  React, {useReducer} from 'react':



function reducer(state,action){

return {

...state,

[action.name]:action.value

};

}

const Info =()=>{

const [state,dispatch]=useReducer(reducer,{

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}

  </div>

  <div>

   <b> 닉네임:</b>{nickname}

  </div>

 </div>

</div>

);

};

export default Info;

- useReducer의 액션은 어떤 값도 사용이 가능

4)useMemo:  함수 컴포넌트 내부에서 발생하는 연산 최적화 가능

<Average.js>

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>

 <input value= {number} onChange={onChange}/>

<button onClick={onInsert}>등록</button>

<ul>

{list.map((value,index)=>(

<li.key={index}>{value}</li>

))}

</ul>

<div>

<b>평균값:</b>{avg}

</div>

</div>

);

};

export default Average;

● useMemo 정리

- import 통해 불러옴

- 렌더링하는 과정에서 특정 값이 바뀌었을 때만 연산을 실행, 원하는 값이 바뀌지 않았다면 이전에 연산했던 결과를 다시 사용

 

5)useCallback: 렌더링 성능을 최적화하는 상황에서 사용, 만들어 놨던 함수를 재사용 가능

<Average.js>

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(() => {

 const nextList = list.concat(parseInt(number));

setList(nextList);

setNumber("");

},[number,list]); // number 혹은 list가 바뀌었을 때만 함수 생성

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

return(

<div>

<Input value={number} onChange={onChange}/>

<button onClick={onInsert}>등록</button>

<ul> 

{list.map((value,index)=>(

<li.key={index}>{value}</li>

))}

</ul>

<div>

<b>평균값:</b>{avg}

</div>

</div>

);

};

export default Average;

 

● useCallback 정리

- import 통해 불러옴

-  첫 번째 파라미터: 생성하고 싶은 함수, 두번째 파라미터: 배열

*배열- 어떤 값이 바뀌없을 때 함수를 새로 생성해야 하는지 명시

- 비어 있는 배열을 넣게 되면 컴포넌트가 렌더링 될때 만들었던 함수를 계속해서 재사용

*배열 안에 number와 list를 넣게 되면 인풋 내용 변경 or  새로운 항목 추가 시 새로 만들어진 함수 사용

- 함수 내부에서 상태 값에 의존해야 할 때는 그 값을 반드시 두번 파라미터 안에 포함시키기

 

6)useRef: 함수 컴포넌트에서 ref를 쉽게 사용할 수 있도록 해 줌

● useRef 정리

-useRef를 사용하여 ref를 설정하면 useRef를 통해 만든 객체 안의 current 값이 실제 엘리먼트를 가리킴

-컴포넌트 로컬 변수를 사용해야 할 때도 useRef 활용 가능

*로컬변수: 렌더링 상관없이 바뀔 수 있는 값

'CS > 프로그래밍' 카테고리의 다른 글

CSS in JS  (1) 2024.01.13
화살표 함수와 일반 함수  (0) 2024.01.08
스코프, 스코프 체인  (1) 2024.01.02
Context API  (1) 2024.01.01
JS, 이벤트 바인딩(Event Binding)  (0) 2023.12.26