Redux Toolkit

IvanSelah·2022년 6월 4일
0

📌 리듀서 함수내에서는 사이드 이펙트가 없고 동기식이여야 합니다.
따라서, 비동기식 코드는 리듀서 함수에 들어가면 안됩니다.

⭕️ useEffect 내에 모두 작성할 수 있지만 많은 것들을 컴포넌트안에 작성하는 것보단 
분리해서 작성하는 것이 컴포넌트를 린상태로 깔끔하게 유지할 수 있다.

  useEffect(() => {
    if (isIntial) {
      isIntial = false;
      return;
    }

    dispatch(sendCartData(cart));
    ⭐️
    // 함수를 반환하는 것도 허용한다. (리덕스툴킷을 사용한다면 가능)
    // 함수작업을 디스패치 하는 것으로 확인되면 해당 함수를 자동으로 실행합니다.
    // 그리고 디스패치를 인수를 준다.
  }, [cart, dispatch]);


export const sendCartData = (cart) => {
  return async (dispatch) => {  // ⭐️ dispatch를 인수로 받음
    dispatch(
      uiActions.showNotification({
        status: 'pending',
        title: 'Sending...',
        message: 'Sending cart data!',
      })
    );

    const sendRequest = async () => {
      const res = await fetch('https://jsonplaceholder.typicode.com/todos/1', {
        method: 'PUT',
        body: JSON.stringify(cart),
      });

      if (!res.ok) {
        throw new Error('Sending cart data failed.');
      }
    };

    try {
      await sendRequest();
      dispatch(
        uiActions.showNotification({
          status: 'success',
          title: 'Success...',
          message: 'Sent cart data successfully!',
        })
      );
    } catch {
      dispatch(
        uiActions.showNotification({
          status: 'error',
          title: 'Error!',
          message: 'Sending cart data failed!',
        })
      );
    }
  };
};

index.js

import { Provider } from 'react-redux';
import { store } from './store/index';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

store.js

import { createSlice, configureStore } from '@reduxjs/toolkit';

const initialCounterState = { counter: 0, isVisible: false };

const counterSlice = createSlice({
  name: 'counter',
  initialState: initialCounterState,
  reducers: {
    increase(state, action) {
      state.counter = state.counter + action.payload; // payload란 이름은 정해져있음
    },
    decrease(state, action) {
      state.counter = state.counter - action.payload;
    },
    isVisible(state) {
      state.isVisible = !state.isVisible;
    },
  },
});

const initialAuthState = { isAuth: false };

const authSlice = createSlice({
  name: 'auth',
  initialState: initialAuthState,
  reducers: {
    login(state) {
      state.isAuth = true;
    },
    logout(state) {
      state.isAuth = false;
    },
  },
});

// ⭐️ 여러개 리듀서 설정
export const store = configureStore({
  reducer: { counter: counterSlice.reducer, auth: authSlice.reducer },
});

export const counterActions = counterSlice.actions;
export const authActions = authSlice.actions;

counter.js

import { useSelector, useDispatch } from 'react-redux';
import { counterActions } from '../store/index';

const Counter = () => {
  const { counter, isVisible } = useSelector((state) => state.counter) 
  // ⭐️ 여러개의 리듀서가 있을 경우 해당하는 reducer 접근을 위해 키값으로 접근
  const dispatch = useDispatch();
  const toggleCounterHandler = () => {
    dispatch(counterActions.isVisible());
  };
  return (
    <main className={classes.counter}>
      <h1>Redux Counter</h1>
      {isVisible && <div className={classes.value}>{counter}</div>}
      <div>
        <button onClick={() => dispatch(counterActions.increase(5))}>increase</button> // action.payload = 5;
        <button onClick={() => dispatch(counterActions.decrease(3))}>decrease</button> // action.payload = 3;
      </div>
      <button onClick={toggleCounterHandler}>Toggle Counter</button>
    </main>
  );
};

export default Counter;
profile
{IvanSelah : ["꿈꾸는", "끊임없이 노력하는", "프론트엔드 개발자"]}

0개의 댓글