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官网