Next.js ts redux/toolkit状态管理

目录

介绍

安装依赖

初始化store

1、在src下创建store文件夹,

2、创建最简单的slice切片

3、创建入口文件index.ts

4、创建hooks.ts

在_app.tsx中注入store

tsx中使用store

payload

createAsyncThunk

效果


介绍

@reduxjs/toolkit是Redux 官方提供的一个工具集,旨在简化和改善 Redux 应用的开发体验。它包含一些工具函数和约定,可以帮助你更快、更轻松地构建和维护 Redux 应用。

方法:

  • configureStore: 创建Redux store
  • createSlice :用于创建state和reducer
  • createAsyncThunk:用于处理异步操作,并自动创建了三个状态(pending、fulfilled、rejected)对应于异步操作的不同阶段。
  • ...

类型:

  • PayloadAction:用于定义往reducer传入action的类型

安装依赖

npm i @reduxjs/toolkit react-redux

yarn add @reduxjs/toolkit react-redux

初始化store

1、在src下创建store文件夹,

2、创建最简单的slice切片

import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit';
import type { RootState } from '.';
interface CounterStateProps {  // state 类型
  value: number;
}
const initialState: CounterStateProps = {  // state数据初始化
  value: 0,
};
export const counterSlice = createSlice({
  name: 'counter',
  initialState,  // state
  reducers: {
    decrementOne: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload;
    }
  }
})
export const { decrementOne, incrementByAmount } = counterSlice.actions;  // 导出action
export const selectCount = (state: RootState) => state.count.value;  // 导出state的值
export default counterSlice.reducer;  // 导出reducer

3、创建入口文件index.ts

import { configureStore } from '@reduxjs/toolkit'
import counterReducers from './counterSlice'
const store = configureStore({
  reducer: {
    count: counterReducers
  }
})
export type RootState = ReturnType<typeof store.getState>  // 导出类型被hook所使用
export type AppDispatch = typeof store.dispatch
export default store

4、创建hooks.ts

import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './'

export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

至此store结构

在_app.tsx中注入store

import { AppProps } from 'next/app';
import { Provider } from 'react-redux';
import Header from '@/components/Header';
import store from '@/store'
export default function MyApp({ Component, pageProps } :AppProps) {
    return (
        <Provider store={store}>
            <Header/>
            <Component {...pageProps} />
        </Provider>
    )
}

tsx中使用store

import { useAppSelector, useAppDispatch } from '@/store/hooks'
import { selectCount, decrementOne ,incrementByAmount  } from '@/store/counterSlice'
export default function Redux() {
  const count = useAppSelector(selectCount)
  const dispatch = useAppDispatch()
  return (
    <>
      <div>value: {count}</div>
      <div>
        <button onClick={() => dispatch(decrementOne())}>increment</button>
        <button onClick={() => dispatch(incrementByAmount(1))}>incrementByAmount</button>
      </div>
    </>
  )
}

useAppSelector用于从store中取出数据

useAppDispatch用于派发reducer,对state进行操作,类似vuex里的mutation

payload

将传递给reducer的action做预处理

  reducers: {
    increment: {
      reducer(state, action: PayloadAction<{title: number; content: number; value:number}>) {
        state.value +=  action.payload.value
      },
      prepare(value: number) {
        return {
          payload: {
            title: 1,
            content: 2,
            value
          },
        };
      }
    },
 }
//tsx

<button onClick={() => dispatch(increment(1))}>increment</button>

dispatch(increment(1)) 后会先走prepare,传入参数value为1,做一些逻辑处理,返回payload,

处理的数据将被reducer的actionPayload所接收。

createAsyncThunk

createAsyncThunk是 Redux Toolkit 提供的一个用于创建处理异步操作的 thunk 函数的辅助函数

import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit';
import type { RootState } from '.';

// 异步操作
export const fetchList = createAsyncThunk('counter/fetchList', async () => {
  const response = await fetch(`http://127.0.0.1:3000/api/v1/list`);
  return await response.json();
});

interface CounterStateProps {
  listLoading: boolean;
  listError: string;
  list: any[];
}

const initialState: CounterStateProps = {
  listLoading: false,
  listError: '',
  list: [],
};

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    cleartListError: (state) => {
      state.listError = '';
    },
  },
  extraReducers(builder) {
    builder.addCase(fetchList.pending, (state) => {
      state.listLoading = true;
    })
    builder.addCase(fetchList.fulfilled, (state, action: PayloadAction<{data?: any, message?: string}>) => {
      const { data, message } = action.payload
      message ? state.listError = message : state.list = data.data;
      state.listLoading = false;
    })
    builder.addCase(fetchList.rejected, (state) => {
      state.listLoading = false;
    });
  },
})
export const { cleartListError } = counterSlice.actions;
export const selectList = (state: RootState) => state.counter.list;
export const selectListLoading = (state: RootState) => state.counter.listLoading;
export const selectListError = (state: RootState) => state.counter.listError;

export default counterSlice.reducer;

用createAsyncThunk创建异步操作,第一个参数是标识符,用于被Redux DevTools所记录

第二个异步回调的返回值传递给

用builder.addCase监听fetchList 异步操作,有三个状态pending、fulfilled、rejected,根据三种状态设置loading和error

在tsx中应用

import { useAppSelector, useAppDispatch } from '@/store/hooks'
import { selectListLoading, selectListError, selectList, fetchList, cleartListError  } from '@/store/counterSlice'
import { Skeleton, message } from 'antd'
import { useEffect } from 'react'
export default function Redux() {
  const [messageApi, contextHolder] = message.useMessage();
  const listLoading = useAppSelector(selectListLoading)
  const listError = useAppSelector(selectListError)
  const list = useAppSelector(selectList)
  const dispatch = useAppDispatch()
  const warning = (msg: string) => {
    messageApi.open({
      type: 'warning',
      content: msg,
    });
  };
  useEffect(() => {
    if(listError) {
      warning(listError)
      dispatch(cleartListError())
    }
  }, [listError])

  return (
    <>
      { contextHolder }
      <div>
        <button onClick={() => dispatch(fetchList())}>获取List</button>
      </div>
      <div>
        {
          listLoading ? 
          <Skeleton active /> :
          list.map((item, idx) => (
            <div key={idx}>{item.name}: {item.counter}</div>
          ))
        }
      </div>
    </>
  )
}

效果

success

error

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值