React-Redux初学笔记

96 阅读3分钟

React-Redux

基本概念介绍:

Redux 本身是一个独立的库,可以与任何 UI 层或框架一起使用,包括 React、Angular、Vue、Ember 和 vanilla JS。虽然 Redux 和 React 通常一起使用,但它们是相互独立的。 React-Redux是React的官方推荐状态管理工具之一,React Redux 是 React 的官方 Redux UI 绑定库,如果您同时使用 Redux 和 React,则还应该使用 React Redux 来绑定这两个库。通过使用React-Redux,React组件可以轻松地获取Redux存储中的状态并在其渲染过程中使用它们。

基本使用:

这里我们将使用TypeScript语言进行讲解

依赖安装:

npm install @reduxjs/toolkit react-redux

新建一个store.ts文件:

src/app/store.ts

import { configureStore } from '@reduxjs/toolkit'

const store = configureStore({  
    reducer: {  
        counter: counterReducer
    },  
})  
  
// 从store中获取RootState` and `AppDispatch`的类型,以方便后续使用
export type RootState = ReturnType<typeof store.getState>  
// 推断出的类型为 {counter: counterReducer}  
export type AppDispatch = typeof store.dispatch
export default store

在根组件中传入store:

要使用redux,需要用<Provider></Provider>包含我们<App/>,并将store进行传递 src/index.ts

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import {Provider} from "react-redux";
import store from "./app/store";

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

新建一个hooks.ts文件:

src/app/hooks.ts

import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'  
import type { RootState, AppDispatch } from './store'  
  
// Use throughout your app instead of plain `useDispatch` and `useSelector`  
export const useAppDispatch: () => AppDispatch = useDispatch  
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

虽然RootState和AppDispatch类型已经可以直接导入到每个组件中进行使用,但最好创建useDispatch和useSelector的hooks以便在应用程序中使用。 原因主要有以下几点:

  • 省去每次useSelector都需要输入(state: RootState)
  • 对于useDispatch,默认Dispatch类型不知道 thunk,使用AppDispatch以正确分派thunk。同时避免出现使用useDispatch时,忘记导入AppDispatch的问题。
  • 由于这些是实际变量,而不是类型,因此在单独的文件中定义它们非常重要,定义在app/hooks.ts而不是在app/store.ts文件中。这使得能在任何需要的地方导入并使用hooks,避免潜在的循环导入依赖问题。

创建一个Slice,并定义Slice的状态和操作:

src/features/counter/counterSlice.ts

import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import type { RootState } from '../../app/store'
// 定义slice的state类型
interface CounterState {
    value: number
}
// 定义初始状态
const initialState: CounterState = {
    value: 0
}
// 创建slice,接收三个参数,名称,初始态以及一些reducer操作
export const counterSlice = createSlice({
    name: 'counter',
    initialState,
    reducers: {
        increment: (state) => {
            state.value += 1
        },
// 使用PayloadAction可以声明接收的类型
        incrementByAmount: (state, action: PayloadAction<number>) => {
            state.value += action.payload
        },
    },
})
export const { increment, incrementByAmount } = counterSlice.actions
// 这里的定义,使得使用useAppSelector变得更加方便
export const selectCount = (state: RootState) => state.counter.value
export default counterSlice.reducer

定义initialState使得reducers中的函数能够推断出state的类型。这里对RootState的导入是一个循环导入,但是编译器会识别并正确处理这里。 有的时候,你需要定义每个变量的初始值,使用as关键字强制转换为该类型即可:

const initialState: CounterState = {
} as CounterState

在组件中使用:

src/features/counter/Counter.tsx

import React, { useState } from 'react'  
  
import { useAppSelector, useAppDispatch } from 'app/hooks'  
  
import { decrement, increment } from './counterSlice'  
  
export const Counter = () => {  
    // 等价于 const count = useAppSelector((state) => state.counter.value),由于我们有过定义,可直接使用
    const count = useAppSelector(selectCount)
    // dispatch在调用时,传入对应的reducers函数以及参数即可,例如dispatch(incrementByAmount(10))
    const dispatch = useAppDispatch()  
    return (
        <div className='container'>
            <h3>这是一个计数器,当前计数为: </h3>
            <text>{count}</text>
            <button
                className='button'
                onClick={()=>{
                    dispatch(incrementByAmount(10))
                }}>
                增加计数
            </button>
        </div>
    )
}

其他用法:

除了基本用法,redux还提供一些别的用法,如connect函数的使用 参考文档:react-redux官网