Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
February 25, 2022 08:54 am GMT

Redux Toolkit & its usage

As a result of Redux Toolkit, you don't have to worry about a lot of boilerplate when using Redux, making your app easier to adopt and implement Redux. The toolkit comes preloaded with the tools you might need when building a Redux app. Moreover, we can also customize the given configurations to suit our specific needs.

Installation
@reduxjs/toolkit comes preloaded with the redux dependencies as well as some essential middlewares.

  • Redux Toolkit
yarn add @reduxjs/toolkit
  • Redux
yarn add redux yarn add react-redux yarn add redux-immutable-state-invariant yarn add redux-thunk yarn add redux-devtools-extension

Store Creation
For Redux Toolkit, configureStore internally calls combineReducers to create the rootReducer, so that you don't have to worry about creating it manually. As well as configuring a few essential middlewares internally, it also helps you write clean and error-free code. These settings can be modified as needed according to the official documentation.

  • Redux Toolkit
import { configureStore } from '@reduxjs/toolkit'import filter from '...'import movie from '...'export default configureStore({  reducer: {    filter,    movie,  },})
  • Redux
import { combineReducers, applyMiddleware, createStore } from "redux"import reduxImmutableStateInvariant from 'redux-immutable-state-invariant'import thunk from 'redux-thunk'import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProduction'import filter from '...'import movie from '...'// Custom middlewares based on redux-immutable-state-invariantconst immutableStateInvariant = // deeply compares state values for mutations. // It can detect mutations in reducers during a dispatch, and also mutations that // occur between dispatches (such as in a component or a selector). When a // mutation is detected, it will throw an error and indicate the key path for // where the mutated value was detected in the state tree.const serializableStateInvariant = // a custom middleware created specifically // for use in Redux Toolkit. Similar in concept to immutable-state-invariant, // but deeply checks your state tree and your actions for non-serializable values // such as functions, Promises, Symbols, and other non-plain-JS-data values. // When a non-serializable value is detected, a console error will be printed // with the key path for where the non-serializable value was detected.const middleware = process.env.NODE_ENV !== 'production' ?  [thunk, immutableStateInvariant, serializableStateInvariant] :  [thunk];const rootReducer = combineReducers({   filter,   movie, })export default createStore(rootReducer, composeWithDevTools(  applyMiddleware(...middleware)))

Creating reducers and sync actions (aka, slices)

Redux Toolkit introduces a new concept called slices, which is essentially a consolidated object containing the reducer and all the synchronous actions. No more action types or types of actions, and the state can now be mutated.

  • Redux Toolkit
import { createSlice } from '@reduxjs/toolkit'const sliceName = 'movie'const movieSlice = createSlice({  name: sliceName,  initialState: {    entities: [],    totalEntities: 0,    error: '',    loading: false,  },  reducers: {    resetMovies: (state) => {      state.entities = []      state.totalEntities = 0      state.error = ''      state.loading = false    },  },})export const { resetMovies } = movieSlice.actionsexport default movieSlice.reducer
  • Redux
const initialState = {  entities: [],  totalEntities: 0,  error: '',  loading: false,}const RESET_MOVIES = 'RESET_MOVIES'export const resetMovies = () => ({  type: RESET_MOVIES})export default function movie(state = initialState, action) {  switch (action.type) {    case RESET_MOVIES:      return {        entities: [],        totalEntities: 0,        error: '',        loading: false,      }    default:      return state  }}

Creating async actions (aka, thunks)
Additionally, Redux Toolkit includes the createAsyncThunk function. It gives us 3 implied sync actions for every thunk to be processed in our reducer, namely .pending, .fulfilled and .rejected. Therefore, we do not need to define actions for each state. We get 3 implied sync actions for each thunk to be processed in our reducers. These are <thunkStringName>.pending , <thunkStringName>.fulfilled and <thunkStringName>.rejected.

  • Redux Toolkit
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'const sliceName = 'movie'export const fetchMovies = createAsyncThunk(  `${sliceName}/fetchMovies`,  (_, { getState }) => {    const { searchTerm, page, type } = getState().filter    return movieAPI.fetchBySearch(searchTerm, page, type)  })const movieSlice = createSlice({  ...  extraReducers: {    [fetchMovies.pending]: (state) => {      state.loading = true    },    [fetchMovies.fulfilled]: (state, action) => {      state.entities = action.payload.Search      state.totalEntities = action.payload.totalResults      state.error = ''      state.loading = false    },    [fetchMovies.rejected]: (state, action) => {      state.entities = []      state.totalEntities = 0      state.error = action.error.message      state.loading = false    },  },})
  • Redux
...const FETCH_MOVIES_PENDING = 'FETCH_MOVIES_PENDING'const FETCH_MOVIES_FULFILLED = 'FETCH_MOVIES_FULFILLED'const FETCH_MOVIES_REJECTED = 'FETCH_MOVIES_REJECTED'...export const fetchMoviesPending = () => ({  type: FETCH_MOVIES_PENDING})export const fetchMoviesFulfilled = (result) => ({  type: FETCH_MOVIES_FULFILLED,  payload: result})export const fetchMoviesRejected = (error) => ({  type: FETCH_MOVIES_REJECTED,  payload: error})export function fetchMovies() {  return async function (dispatch, getState) {    dispatch(fetchMoviesPending())    const { searchTerm, page, type } = getState().filter    try {      const result = await movieAPI.fetchBySearch(searchTerm, page, type)      dispatch(fetchMoviesFulfilled(result))    } catch (error) {      dispatch(fetchMoviesRejected(error))    }  }}export default function movie(...) {  switch (action.type) {    ...    case FETCH_MOVIES_PENDING:      return {        ...state,        loading: true,      }    case FETCH_MOVIES_FULFILLED:      return {        entities: action.payload.Search,        totalEntities: action.payload.totalResults,        error: '',        loading: false,      }    case FETCH_MOVIES_REJECTED:      return {        entities: [],        totalEntities: 0,        error: action.error.message,        loading: false,      }    ...  }}

Usage In React APP
Once the store and the slices have been created, you can setup Redux in your app the same way as you've always have.

import React from 'react'import ReactDOM from 'react-dom'import App from './App'import store from './store'import { Provider } from 'react-redux'ReactDOM.render(  <React.StrictMode>    <Provider store={store}>      <App />    </Provider>  </React.StrictMode>,  document.getElementById('root'))
  • Movies/index.jsx
import React, { useEffect } from 'react'import Movies from './presenter'import { useSelector, shallowEqual, useDispatch } from 'react-redux'import { search } from '../../services/filter/slice'export default () => {  const { entities, totalEntities, error, loading } = useSelector(    (state) => state.movie,    shallowEqual  )  const searchTerm = useSelector((state) => state.filter.searchTerm)  const dispatch = useDispatch()  useEffect(() => {    dispatch(search(searchTerm))  }, [dispatch, searchTerm])  return (    <Movies      entities={entities}      totalEntities={totalEntities}      error={error}      loading={loading}    />  )}

*Github * https://github.com/batbrain9392/redux-tutorial


Original Link: https://dev.to/alter80/redux-toolkit-1d0p

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To