React 상태-(2): useReducer

김수민·2023년 1월 13일
0

React

목록 보기
11/17

useState

  • useState는 설정하고 싶은 상태를 직접 설정하고 지정하여 상태를 업데이트한다.
  • useReducer는 action객체를 기반으로 상태를 업데이트 한다.

useReducer

Dispatch(Action) 👉 Reducer(state,Action)

Dispatch로 Action을 전달하면 state 및 Action을 받은 Reducer가 호출된다.
이 Reducer가 받아온 값을 통하여 state를 업데이트 시켜준다.

  • Dispatch
    reducer를 호출하기 위하여 거쳐야하는 함수
    정보는 Action객체를 이용하여 전달한다.

  • Reducer
    state를 업데이트 위하여 거쳐야하는 함수
    dispatch를 통해 호출되어 state 및 Action을 매개변수로 받아온다.

  • state
    여러개의 상태값을 관리해야할 때 사용한다.

const [A,dispatch]= useReducer(함수명B,초기값)
👉 return[A, dispatch]
// 1️⃣ A라는 변수를 가지는 state를 작성한다.

function 함수명B(state,action){
	switch(action.type){
      case "타입명":
        return '타입이 "타입명"일때 실행 되어 상태가 될 구문';
    }
}
// 2️⃣ "타입명"에 따른 결과를 작성한다.
// 함수명B는 reducer로, dispatch를 통해 호출되어 state및 Action을 매개변수로 받아온다.

dispatch({type:"타입명"}) 
// 3️⃣ dispatch 및 지정한 타입명으로 상태를 호출한다.

기본적인 useReducer 사용법은 위와 같다.

응용

import Header from './components/Header';
import { useReducer } from 'react';

//------------------------state 초기값 설정------------------------//
const initialState={
  input:"",
  todos:[
    {id:1, text:"내용1", isDone: false},
    {id:2, text:"내용2", isDone: false},
  ],
  id: 3
}

//------------------------reducer 함수 선언------------------------//
function reducer(state,action){
  switch (action.type) {
    case 'addTodo': //할일 추가
      return {
        ...state,
        todos: [...state.todos, action.todo],
        id: state.id+1,
        input: ""
      }
    case 'changeInput': //input값 변경
      return {
        ...state,
        input: action.payload
      }
    default:
      return state;
  }
}

//------------------------state 요청------------------------//
function App() {
  // 상태 선언하기
  const [state,dispatch]= useReducer(reducer,initialState)
  const {todos, input, id}= state;
  // input update 요청
  const onChange=(e)=>{
    dispatch({type: 'changeInput', payload: e.target.value})
  };
  // 할일 항목 추가 update 요청
  const addTodo = ()=>{
    dispatch({
      type:'addTodo',
      todo: {id:id,text:input,isDone:false}
    })
  };
 
  //------------------------return------------------------//
  return (
    <div className="App">
      <Header input={input} onChange={onChange} addTodo={addTodo}/>
    </div>
  );
}

export default App;
import React from 'react';

const Header = ({input,onChange,addTodo}) => {
	return (
			<>
				<input value={input} onChange={onChange}/>
				<button onClick={addTodo}>+</button>
			</>
	);
};

export default Header;

전역 useReducer 사용하기

axios를 이용하여 useReducer를 전역에서 사용 할 수 있도록 작성한다.

import { useEffect, useReducer } from "react"

// 초기값 지정
const initialState={
	users: null,
	loading: false,
	error: null
}

// reducer 함수 및 type 지정
function reducer(state,action){
	switch (action.type) {
		case 'users':
			return{...state, users:action.data, loading: false}
		case 'loading': 
			return{...state, loading: true}
		case 'error': 
			return{...state, error: action.payload}
		default:
			break;
}};

// 매개변수로 callback 및 deps 받아오는 함수 useAsync 생성 
const useAsync = (callback,deps=[]) => {
	const [state,dispatch]= useReducer(reducer,initialState)
    // useReducer를 사용하여 상태와 상태를 업데이트해줄 dispatch 함수를 받아옴
	const fetchUsers= async()=>{
		try{
			dispatch({type: 'loading'})
			const response= await callback();
			dispatch({type: 'users', data: response.data})
		}
		catch(e){
			dispatch({type: 'error', payload: e})
		}
	}
	useEffect(()=>{
		fetchUsers();
	},deps)
  // 페이지가 처음 실행 될 때 fetchUsers()를 한번 실행시키고,
  // deps가 변경되면 fetchUsers()를 실행시킨다.
  
  return [state,fetchUsers];
  // 아래 Users함수에서 사용된다.
};
export default useAsync;
import axios from 'axios';
import React from 'react';
import useAsync from '../hooks/useAsync';

async function getUsers(){
	const response= await axios.get(
		'//jsonplaceholder.typicode.com/users'
	)
	return response;
};
// Users의 callback으로 들어갈 값(주소값)을 지정

const Users = () => {
	const [state,refetch]=useAsync(getUsers,[])
    // useAsync 함수에서 return된 [state,fetchUsers]를 담았다
    // state는 초기값 initialState을 기반으로 바뀌는 상태이다. 
    // refetch는 상황에 따라 state를 바꾸는 함수이다.
	const {users, loading, error}= state;
	if(loading) return <div>로딩중...</div>
	if(error) return <div>에러가 발생했습니다.</div>
	if(!users) return null;

	return (
		<div>
			<ul>
				{users.map(user=><li key={user.id}>{user.username} {user.name}</li>)}
			</ul>
			<button onClick={refetch}>재요청</button>
		</div>
	);
};

export default Users;
profile
sumin0gig

0개의 댓글