Redux

1. 시작

  • 설치
npm install redux react-redux
  • store 생성
import {createStore} from 'redux'

function reducer(state, action) {
    // ...
    return newState
}

const store = createStore(reducer);

export default store

2. Provider

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

function App() {
  return (
    <div className="App">
      <h1>Root</h1>
      <div className="Grid">
        <Provider store={store}>
          <Left1></Left1>
          <Right1></Right1>
        </Provider>
      </div>
    </div>
  );
}
export default App;

3. Hooks

  • useSelector(Left3.jsx)
import { useSelector } from "react-redux"

export default function Left3() {
  const number = useSelector((state) => state.number);

  return (
    <div>
      <h3>Left3 : {number}</h3>
    </div>
  )
}
  • useDispatch(Right3.jsx)
import { useDispatch } from "react-redux"

export default function Right3() {
  const dispatch = useDispatch();
  return (
    <div>
      <h3>Right3</h3>
      <button onClick={() => {dispatch({type:'PLUS'})}}>+</button>
    </div>
  )
}

4. Redux Toolkit

createStore 대신(from redux) 사용하게 될 createSlice 제공

조금 더 직관적인 코드 작성 가능

유지보수 간편

Install

$ npm install @reduxjs/toolkit react-redux

Create a Redux Store & Add Slice Reducers to the Store

  • app/store.js
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '../features/counter/counterSlice'

// 작성한 slice를 store에 등록
export default configureStore({
  reducer: {
    counter: counterReducer,
  },
})

Provide the Redux Store to React

  • index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import store from './app/store'
import { Provider } from 'react-redux'

// As of React 18
const root = ReactDOM.createRoot(document.getElementById('root'))

// 최상위 컴포넌트에 Provider
root.render(
  <Provider store={store}>
    <App />
  </Provider>
)

Create a Redux State Slice

  • features/counter/counterSlice.js
import { createSlice } from '@reduxjs/toolkit'

// 기본 상태 및 상태관리 reducer 등록
export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,
  },
  reducers: {
    increment: (state) => {
      // Redux Toolkit allows us to write "mutating" logic in reducers. It
      // doesn't actually mutate the state because it uses the immer library,
      // which detects changes to a "draft state" and produces a brand new
      // immutable state based off those changes
      state.value += 1
    },
    decrement: (state) => {
      state.value -= 1
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload
    },
  },
})

// dispatch를 위한 export
export const { increment, decrement, incrementByAmount } = counterSlice.actions

// The function below is called a thunk and allows us to perform async logic. It
// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
// will call the thunk with the `dispatch` function as the first argument. Async
// code can then be executed and other actions can be dispatched
export const incrementAsync = (amount) => (dispatch) => {
  setTimeout(() => {
    dispatch(incrementByAmount(amount))
  }, 1000)
}

// The function below is called a selector and allows us to select a value from
// the state. Selectors can also be defined inline where they're used instead of
// in the slice file. For example: `useSelector((state) => state.counter.value)`
export const selectCount = (state) => state.counter.value

export default counterSlice.reducer

Use Redux State and Actions in React Components

  • features/counter/Counter.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from './counterSlice'
import styles from './Counter.module.css'

// useSelector를 이용하여 store에 등록된 counter slice에서 value 값을 가져옴
export function Counter() {
  const count = useSelector((state) => state.counter.value)
  const dispatch = useDispatch()

  return (
    <div>
      <div>
        <button
          aria-label="Increment value"
          onClick={() => dispatch(increment())}
        >
          Increment
        </button>
        <span>{count}</span>
        <button
          aria-label="Decrement value"
          onClick={() => dispatch(decrement())}
        >
          Decrement
        </button>
      </div>
    </div>
  )
}

정리

현재 리액트 최신버전에서는 createStore을 권장하지 않고 있습니다.

그래서 redux-toolkit에 익숙해져야겠습니다.

+ Recent posts