useReducerDispatch(Action) → Reducer(state, Action)
Dispatch로Action을 전달하면state및Action을 받은Reducer가 호출된다.
이Reducer가 받아온 값을 통하여state를 업데이트 시켜준다.
Dispatchreducer를 호출하기 위하여 거쳐야하는 함수
정보는 Action객체를 이용하여 전달한다.
Reducerstate를 업데이트 위하여 거쳐야하는 함수
dispatch를 통해 호출되어 state 및 Action을 매개변수로 받아온다.
state여러개의 상태값을 관리해야할 때 사용한다.
useStateuseState는 설정하고 싶은 상태를 직접 설정하고 지정하여 상태를 업데이트한다.
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;
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;