useReducer

hanyoko·2023년 6월 23일

REACT

목록 보기
8/15
post-thumbnail

useReducer

Dispatch(Action)Reducer(state, Action)

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

Dispatch

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


Reducer

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


state

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


useState

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


useReducer 사용방법

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 및 지정한 타입명으로 상태를 호출한다.
import React, { useReducer } from 'react';
function reducer(state, action){
    //action에 따라 상태를 업데이트 시키는 조건문
    switch(action.type) {
            //객체.key
        case 'increase':
            return state + 1;
        case 'decrease':
            return state - 1;
        default:
            return state;
    }
}
const Counter2 = () => {
    const [number, dispatch] = useReducer(reducer,0);
                //reducer를 실행시키기 위해 필요하다.
    const onIncrease = () => {
        dispatch({
            type: 'increase'
        })
    }
    const onDecrease = () => {
        dispatch({
            type: 'decrease'
        })
    }
    return (
        <div>
            <h2>{number}</h2>
            <button onClick={onIncrease}>+1</button>
            <button onClick={onDecrease}>-1</button>
        </div>
    );
};

export default Counter2;

사용예시

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(함수, 초기값);
  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}
    })
  };
  // //input 값 업데이트 요청
  const onChange = (e) => {
  	dispatch({
       type: 'changeInput',
       payload: e.target.value
     })
   }
  //할일 항목 추가 업데이트 요청
  const addTodo = () => {
  	dispatch({
      type: "addTodo",
      todo: { id: id, text: input, idDone: false }
    })
  }
  //todo 삭제 업데이트 요청
  const deleteTodo = (id) => {
    dispatch({
      type: "deleteTodo",
      id: id
    })
  }
  const toggleTodo = (id) => {
    dispatch({
      type: "toggleTodo",
      id: id
    })
  }
 
  //------------------------return------------------------//
  return (
    <UserDispatch.Provider value={dispatch}>
      <div className="App">
        <Header input={input} id={id} />
        {/* addTodo={addTodo} */}
        <TodoLists todos={todos} />
         {/* TodoLists 태그 안에 있던 toggleTodo={toggleTodo} deleteTodo={deleteTodo}*/} 
      </div>
    </UserDispatch.Provider>
  );
}
}

export default App;
import React, { useContext } from 'react';
import { UserDispatch } from '../App';

const Header = ({input, id}) => {
    const dispatch = useContext(UserDispatch);

    const onChange = (e) => {
        dispatch({
            type: 'changeInput',
            payload: e.target.value
        })
    }
    const addTodo = () => {
        dispatch({
            type: 'addTodo',
            todo: {id: id, text: input, isDone: false}
        })
    }
    return (
        <div>
            <h2>to do list</h2>
            <div>
                <input value={input} onChange={onChange}/>
                <button onClick={addTodo}>+</button>
            </div>
        </div>
    );
};

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;

0개의 댓글