什么是Redux?它有什么用
Redux 是一个用于 JavaScript 应用的状态管理库,通常与 React 一起使用。它帮助开发者管理应用中各个组件之间的状态,使得状态的变化变得更加可预测和易于调试。
注意:Redux也可以不和React组合使用的哦(通常一起使用)
Redux基本原理
所有的状态都以对象树的方式 (state)
存放于单个 store
中。
唯一改变状态树 (state tree)
的方法是创建 action
:一个描述发生了什么的对象,并将其 dispatch
派发给 store
。 要指定状态树如何响应 action
来进行更新,你可以编写纯 reducer
函数,这些函数根据旧 state
和 action
来计算新 state
。
新的 state
被创建后,对象会自动传递给所有注册了监听器的组件,从而触发组件的重新渲染,使得界面始终保持与当前的 state
对象一致。
Redux在React中具体使用的方法
在React中使用redux,官方建议安装两个其他插件 - Redux Toolkit 和 React-Redux
-
Redux Toolkit(RTK)
:官方推荐编写Redux逻辑的方式,是一套工具的集合集,简化书写方式 -
React-Redux
:用来 链接 Redux 和 React 组件的中间件 -
安装方式
npm install @reduxjs/toolkit react-redux
下面我将详细讲解这两个插件的一些具体使用场景和常用函数。
Redux Toolkit(RTK)
非常草率的讲,就是简化Redux的使用方式推出的Toolkit(工具),这个工具中集合了方便使用Redux的一些函数。接下来我们来看一下这些函数是什么?怎么用?有什么用?
createSlice 函数
createSlice
函数的作用是创建一个 Redux 的 slice。它接受一个包含 reducer 函数、slice 名称和初始状态的配置对象,并返回一个包含 reducer 和 action creators 的对象。
参数
name
:slice 的名称,用于标识状态的一部分。initialState
:slice 的初始状态,定义了状态的初始值。reducers
:一个对象,包含一组同步的 reducer 函数,用于更新状态。
返回值
createSlice
返回一个包含以下属性的对象:
name
:slice 的名称。reducer
:一个 reducer 函数,用于处理来自 action creators 的动作并更新状态。actions
:一组 action creators,用于创建派发给 reducer 的动作。
示例
import { createSlice } from '@reduxjs/toolkit';
// 定义初始状态
const initialState = {
count: 0,
};
// 创建一个 Redux slice
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
// 定义同步的 reducer 函数
increment(state) {
state.count += 1;
},
decrement(state) {
state.count -= 1;
},
// 可以接受额外参数的 reducer 函数
incrementByAmount(state, action) {
state.count += action.payload;
},
},
});
// 导出action creators
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
// 导出reducer
export default counterSlice.reducer;
在上面的示例中,我们使用 createSlice
函数创建了一个名为 counter
的 slice。它包含一个名为 count
的状态和三个同步的 reducer 函数:increment
、decrement
和 incrementByAmount
。
通过
increment, decrement, incrementByAmount
派发动作通过
counterSlice.reducer
处理动作
configureStore 函数
configureStore
函数的作用是创建一个 Redux store。它接受一个包含 reducer 函数和其他配置选项的对象,并返回一个 Redux store 实例。
参数
reducer
:一个或多个 reducer 函数,用于处理来自 action creators 的动作并更新状态。- 其他配置选项:包括
middleware
、devTools
等,用于配置 store 的行为。
返回值
configureStore
返回一个 Redux store 实例,它包含以下属性和方法:
getState()
:用于获取当前的状态。dispatch(action)
:用于派发一个动作,以触发状态的更新。subscribe(listener)
:用于添加一个状态变化的监听器,当状态发生变化时会被调用。replaceReducer(nextReducer)
:用于替换当前的 reducer。
示例
import { configureStore } from '@reduxjs/toolkit';
import rootReducer from './reducers'; // 导入根 reducer
// 创建 Redux store
const store = configureStore({
reducer: rootReducer,
// middleware: getDefaultMiddleware => getDefaultMiddleware(), // 使用默认的中间件
// devTools: process.env.NODE_ENV !== 'production', // 在开发环境启用 Redux DevTools
});
export default store
在上面的示例中,我们使用 configureStore
函数创建了一个 Redux store。
我们传入了一个根 reducer rootReducer
,它是一个包含所有 reducer 的对象。我们还配置了默认的中间件,并在开发环境下启用了 Redux DevTools。
React-Redux
想掌握 React-Redux 你首先要把它的概念弄清楚,这很重要!
通俗来讲,
React-Redux
将所有组件分成两大类:UI 组件和容器组件。
- UI组件:负责呈现页面。(React)
- 容器组件:负责管理数据和业务逻辑。(Redux)
有人可能问,Redux和React-Redux的区别是什么? 答案:React-Redux 的主要作用是简化在 React 应用中使用 Redux 的过程,提供方便的方法来连接 Redux store 和 React 组件。
下面我们来说一下React-Redux中常用的组件及方法。
Provider组件
Provider
是React-Redux中的一个高阶组件,它的作用是将 Redux 的 store 传递给整个 React 应用程序,使得所有的组件都能够访问到 Redux 的状态。通过Provider
,我们可以在 React 应用的任何地方使用 Redux 的状态和派发动作。
使用 Provider
的主要好处是,在整个应用程序中,任何一个组件都可以通过 connect
函数或者 useSelector
钩子来访问 Redux store 中的状态,而不需要手动地将 store 传递给每一个组件。这样做的好处有:
- 简化代码: 不需要在每一个组件中手动传递 store,通过
Provider
,store 可以在整个应用程序中自动地传递给需要的组件。 - 避免 prop drilling: 避免了在组件层级结构中进行多层次的 prop 传递,提高了代码的可维护性和可读性。
- 一致性: 所有的组件都使用相同的 Redux store,保证了应用程序中状态的一致性。
示例
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import store from './store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<App />
</Provider>
)
在上面的示例中,我们将 Redux store 通过 Provider 传递给了根组件 <App />
,这样在整个应用程序中的任何地方,我们都可以使用 React-Redux 提供的 hooks 或者高阶组件来访问 Redux 的状态,以及派发 Redux 的动作。
React组件使用store中的数据
useSelector钩子函数
useSelector
是 React-Redux 提供的一个钩子函数,它用于从 Redux store 中选择部分状态。通过useSelector
,我们可以在函数组件中订阅 Redux store 中的状态,并在状态变化时重新渲染组件。
它的作用类似于 connect
方法中的 mapStateToProps
,但是更加简洁和直接。(后面说)
它接受一个选择器函数作为参数,并返回选择器函数计算得到的值。当 Redux store 中的状态发生变化时,组件将会重新渲染,以显示最新的状态。
import { useSelector } from "react-redux"
function App() {
const {count} = useSelector((state) => state.counter)
return <div>{count}</div>
}
export default App
在上面的示例中,我们通过 useSelector
钩子函数选择了 Redux store 中的 counter
状态,并将其赋值给 counter
变量。随后,我们将这个状态显示在组件中,当 Redux store 中的 counter
状态发生变化时,组件将会重新渲染以显示最新的状态。
connect组件
connect
是 React-Redux 提供的一个函数,用于连接 React 组件和 Redux store。上面已经说过 React-Redux 的概念了,按照我的理解,
connect
就是 React 和 Redux 中间的-
mapStateToProps
将Redux store中的状态映射到组件的props:
const mapStateToProps = state => {
return {
count: state.count,
}
}
mapDispatchToProps
将 action creators 映射到组件的 props 中的回调函数:
const mapDispatchToProps = {
increment,
decrement,
}
示例
import React from 'react';
import { connect } from 'react-redux';
import { increment, decrement } from './actions';
function App({ count, increment, decrement }) {
return (
<div>
<button onClick={increment}> + </button>
<p>{count}</p>
<button onClick={decrement}> - </button>
</div>
)
}
const mapStateToProps = state => {
return {
count: state.count,
}
}
const mapDispatchToProps = {
increment,
decrement,
}
// 使用 connect 函数连接组件和 Redux store
export default connect(mapStateToProps, mapDispatchToProps)(App)
在上面的示例中,我们通过 connect
函数将 Redux store 和组件连接起来。我们使用 mapStateToProps
函数将 Redux store 中的 count
状态映射到组件的 count props
中,同时使用 mapDispatchToProps
对象将 increment
和 decrement
action creators 映射到组件的 increment
和 decrement
props 中的回调函数。
export default connect(mapStateToProps, mapDispatchToProps)(App)
可能这里会有小伙伴很迷,这里其实是将 mapStateToProps
和 mapDispatchToProps
中定义的逻辑分别应用到 App
组件上,并将最终生成的容器组件导出。
React组件修改store中的数据
useDispatch钩子函数
useDispatch
是 React-Redux 提供的一个钩子函数,用于在函数组件中获取 Redux store 的 dispatch 函数。通过useDispatch
,我们可以在函数组件中派发 Redux actions,从而改变 Redux store 中的状态。
示例
import { useDispatch, useSelector } from "react-redux"
// 导入actionCreater
import { inscrement, decrement } from "./store/modules/counterSlice"
function App() {
const { count } = useSelector((state) => state.counter)
// 使用useDispatch()函数
const dispatch = useDispatch()
return (
<div>
{/* 加 */}
<button onClick={() => dispatch(inscrement())}> + </button>
{count}
{/* 减 */}
<button onClick={() => dispatch(decrement())}> - </button>
</div>
)
}
export default App
在上面的示例中,我们通过 useDispatch
钩子函数获取了 Redux store 的 dispatch
函数,并将其赋值给 dispatch
变量。随后,我们可以在组件中使用 dispatch
函数来派发 Redux actions,例如在按钮的点击事件处理函数中派发 increment
和 decrement
actions。
Redux异步action处理
虽然 Redux 主要用于处理同步的状态更新,但有时我们需要处理异步的操作,例如从服务器获取数据或执行一些异步任务。在 Redux 中处理异步操作通常需要使用中间件来实现。
相信能看到这的朋友们不至于我长篇大论再给您说异步吧...
Redux Thunk 中间件
将Redux中的异步action处理时,我们不得不提到Redux Thunk。
它是 Redux 提供的一个中间件,它允许我们 dispatch 函数而不仅仅是普通的 action 对象。这样,我们就可以在 action creators 中返回一个函数,而不是一个普通的 action 对象。这个函数可以接受dispatch
和getState
作为参数,并在其中执行异步操作。
示例
在上面的示例中第二点我要做详细的解释(作者刚学的时候绕的非常不舒服)
错误的想法:直接调用fetchChannels()
正确的想法:dispatch(fetchChannels())
原因:当你调用 dispatch(fetchChannels())
时,Redux Thunk 中间件会拦截这个 action,并判断它是否是一个函数。如果是函数,则 Redux Thunk 会执行这个函数,并将 dispatch
方法作为参数传递给它。在这个函数中,你可以进行异步操作,比如发送网络请求。当异步操作完成后,你可以再次使用 dispatch
来派发普通的 action 对象,这样 Redux store 就能够正确地更新状态。