5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Redux-Thunk vs createAsyncThunk(Redux-toolkit)

Posted at

Reduxのthunkは割と鬼門だと思っていて、今回redux-toolkitを勉強するにあたって公式docを読んだのですが、割と分からなかったので比較とメモを兼ねて書いてみました。

Reduxで書く場合

ちょっと面倒くさかったので、1ファイルにかなりまとめて書いてしまいましたが、reduxの方はthunkでAPIを呼ぶ関数を関数で包んでるだけで(ここの部分はまだ勉強中)、単純にload時にAPIを呼ぶ関数内でfetchした値をactionディスパッチで送信しているだけです。

composeEnhancersなどを使っているのは、ChromeのRedux用ツールで可視化するためだけです。

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {Provider} from 'react-redux'
import {applyMiddleware, createStore, compose} from 'redux'
import thunk from 'redux-thunk'

const initState = {
  items: []
}

const rootReducer = (state = initState, action) => {
  switch(action.type) {
    case 'add': return {items: [...state.items, action.payload]}
    default: return state
  }
}



const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(rootReducer, /* preloadedState, */ composeEnhancers(
    applyMiddleware(thunk)
  ));

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
    <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);
reportWebVitals();
App.js
import {useDispatch, useSelector} from 'react-redux'
import {useEffect} from 'react'

const addCreator = (data) => {
  return {type: 'add', payload: data}
}


function App() {
  const items = useSelector(state => state.items)
  const dispatch = useDispatch()

  const fetchData = () => {
    fetch('https://fakestoreapi.com/products')
    .then(res => res.json())
    .then(result => dispatch(addCreator(result)))
  }

  useEffect(()=> {
    fetchData()
  },[])
  return (
    <ul className="App">
      {!items ? (<p>Loading</p>):(items[0].map( i=> <li key={i.id}>{i.title}</li>))}
    </ul>
  );
}

export default App;

Redux-toolkitを使う場合

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {Provider} from 'react-redux'
import {configureStore} from '@reduxjs/toolkit'
import cartReducer from './reducer';


const store = configureStore({
  reducer: cartReducer.reducer
})

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

reportWebVitals();
App.js
import {useSelector, useDispatch} from 'react-redux'
import {useEffect} from 'react'
import { fetchCartList } from "./reducer";


function App() {
  const data = useSelector(state => state.cart.data)
  const dispatch = useDispatch()

  useEffect(() => {
    dispatch(fetchCartList())
  }, [])
  return (
    <div className="App">
      {data.length === undefined? (<p>Loading</p>):(data.map(i=><p>{i.title}</p>))}
    </div>
  );
}

export default App;

ここまでは大したことないですが、以下のcreateAsyncThunkのポイントは、toolkitではcreateAsyncThunkで作成したAPI呼び出しの関数は自動的にredux側でactionを作成してくれ、それぞれpendingfulfilledrejectedとしてわざわざ自分でreducerを用意しなくても、extraReducersの中で各処理を書くことが出来るようです。

また、createAsyncThunkを使ったAPI呼び出しの関数をuseEffectで呼んで処理することが出来てstoreで一緒にapplyMiddleware(thunk)とする必要もありません。

とまあ、大した内容でもないのですが、個人的には割とこのcreateSliceなどにも慣れず公式だとたくさん情報が書いてあるのですがシンプルに使ってみたいだけの時になかなかうまくいかなかったので、今回書いてみました。

reducer.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"


const axios = require("axios");

export const fetchCartList = createAsyncThunk(
  "cart/cartItemLoading",
  () =>
    axios
      .get(`https://fakestoreapi.com/products`)
      .then((response) => response.data)
      .catch((error) => error)
);

const initialState = {
    cart: {
      status: "idle",
      data: {},
      error: {},
    },
  };
  
  const cartSlice = createSlice({
    name: "cart",
    initialState,
    reducers: {},
    extraReducers: {
      [fetchCartList.pending.type]: (state, action) => {
        state.cart = {
          status: "loading",
          data: {},
          error: {},
        };
      },
      [fetchCartList.fulfilled.type]: (state, action) => {
        state.cart = {
          status: "idle",
          data: action.payload,
          error: {},
        };
      },
      [fetchCartList.rejected.type]: (state, action) => {
        state.cart = {
          status: "idle",
          data: {},
          error: action.payload,
        };
      },
    },
  });
  
  export default cartSlice;
5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?