react项目使用redux入门-7-使用@reduxjs/toolkit

@reduxjs/toolkit

场景:获取产品详情

@reduxjs/toolkit 依赖了redux、redux-thunk,所以使用toolkit就不需要额外下载redux,意味着可以再多个框架使用,但是并没有react-redux,所以仍然需要安装react-redux。依赖了redux-thunk,提供了createAsyncThunk方法,可以支持异步

  1. 安装依赖

    npm i react-redux @reduxjs/toolkit --save
    
  2. 入口使用react-reduxProvider组件包裹App组件,并加载数据仓库store : src/index.tsx

    import React from 'react'
    import ReactDOM from 'react-dom'
    import { Provider } from 'react-redux'
    import App from './App'
    import store from 'redux/store.ts'
    
    ReactDOM.render(
      <React.StrictMode>
    		<Providr store={store}>
      		<App/>
      	</Provider>
      </React.StrictMode>
      ,document.getElementById('root')
    )
    
  3. store数据封装

    • 新建目录:src/reduxsrc/redux/productDetail
    • 新建文件:src/redux/store.tssrc/redux/hook.tssrc/redux/productDetail.slice.ts
    mkdir src/redux src/redux/productDetail
    touch src/redux/store.ts src/redux/productDetail/slice.ts
    
    • store.ts
    import {configureStore} from '@reduxjs/toolkit'
    import {productDetailSlice} from './productDetail/slice'
    import languageReducer from './language/reducer'
    
    const rootReducer = combineReducers({
      language: languageReducer,
      productDetail: productDetailSlice.reducer
    })
    
    const store = configureStore({
      reducer: rootReducer,
      middleware: getDefaultMiddleware => [...getDefaultMiddleware()]
    })
    
    export type RootState = ReturnType<typeof store.getState>
    
    export default store
    
    • hook.ts
    import { useSelector as useReduxSelector, TypedUseSelectorHook } from 'react-redux'
    import { RootState } from './store'
    export const useSelector: TypedUseSelectorHook<RootState> = useReduxSelector
    
    • productDetail/slice.ts
    // createAsyncThunk: 方法返回一个函数型action:AsyncThunk<Returned, ThunkArg, {}>
    import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit'
    import axios form 'axios'
    
    interface ProductDetailState = {
      loading: false,
      detail: any,
      error: null | string
    }
    const initialState:ProductDetailState = {
      loading: false,
      detail: {},
      error: null
    }
    
    //  createAsyncThunk 方法,返回一个 函数类型的 action
    export const getDetailAction = createAsyncThunk(
    	'productDetail/getDetailAction', // 异步action的内部命名空间的名称
      async (id:string) => { // payloadCreator
        const { data } = await axios.get(`/product/${id}`)
        return data
      }
    )
    
    export const productDetailSlice = createSlice({
      name: 'productDetail',
      initialState,
      reducers:{},
      extraReducers: {
        // js中[getDetailAction.pending],ts中[getDetailAction.pending.type]是ts需要类型
        [getDetailAction.pending.type]: state => state.loading = true,
        [getDetailAction.fulfilled.type]: (state, action) => {
          state.loading = false
          state.detail = action.payload
        },
        [getDetailAction.rejected.type]: (state, action: PayloadAction<null | string>) => {
          state.loading = false
          state.error = action.payload
        }
      }
    })
    
  4. ProductDetail组件中使用

    import React, { useEffect } from 'react'
    import { useParams } from 'react-router-dom'
    import { Spin } from 'antd'
    // 使用toolkit来进行数据请求
    import { useSelector } from "redux/hooks"; // useSelector是react-redux中的useSelector再次封装过
    import { useDispatch } from "react-redux";
    import { getDetailAction } from "redux/productDetail/slice";
    
    export const DetailView = () => {
      const { touristRouteId } = useParams<{ touristRouteId: string }>()
      
      // 请求数据
      const dispatch = useDispatch()
      const loading = useSelector(({ productDetail }) => productDetail.loading)
      const error = useSelector(({ productDetail }) => productDetail.error)
      const detail = useSelector(state => state.productDetail.detail)
      
      useEffect(() => {
        dispatch(getDetailAction(touristRouteId))
      }, [])
      
      return loading ? (<Spin tip='正在加载...' size='large'/>) :
        (
          <div>
            {detail.title}
        	</div>
      	)
    }
    
    
posted @ 2022-01-20 18:12  shine_lovely  阅读(1302)  评论(0编辑  收藏  举报