Redux 与 React 状态管理精讲:从基础到实战

DZSpace 2024-08-26 11:33:01 阅读 86

引言

Redux 是一个广泛使用的 JavaScript 状态管理库,尤其适用于 React 应用。它提供了一种可预测的方式来管理应用的状态,使得状态的变更变得可控和可追踪。本教程将从 Redux 的基本概念讲起,逐步深入到与 React 结合使用的最佳实践,以及如何处理异步操作和调试。

Redux 简介

Redux 允许你将应用的状态集中存储在一个全局的 store 中,并通过纯函数 reducer 来描述状态的变化。这种集中式的状态管理方式简化了组件间的通信,并且易于调试。

为什么使用 Redux?

独立性:Redux 可以独立于框架运行,不仅限于 React。简化通信:无视组件层级,简化组件间的数据传递。数据流清晰:单向数据流使得状态变更易于追踪和定位问题。调试友好:配套的调试工具如 Redux DevTools 提供了强大的调试支持。

Redux 快速体验

实现一个计数器

不依赖任何框架或构建工具,使用纯 JavaScript 和 Redux API 来实现一个简单的计数器。

定义 <code>reducer 函数,根据 action 返回新的状态。使用 createStore 创建 store 实例。使用 subscribe 订阅状态变化。使用 dispatch 提交 action,触发状态变更。使用 getState 获取最新状态并更新视图。

<button id="decrement">-</button>code>

<span id="count">0</span>code>

<button id="increment">+</button>code>

<script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script> code>

<script>

// 1. 定义reducer函数

// 作用: 根据不同的action对象,返回不同的新的state

// state: 管理的数据初始状态

// action: 对象 type 标记当前想要做什么样的修改

function reducer (state = { count: 0 }, action) {

// 数据不可变:基于原始状态生成一个新的状态

if (action.type === 'INCREMENT') {

return { count: state.count + 1 }

}

if (action.type === 'DECREMENT') {

return { count: state.count - 1 }

}

return state

}

// 2. 使用reducer函数生成store实例

const store = Redux.createStore(reducer)

// 3. 通过store实例的subscribe订阅数据变化

// 回调函数可以在每次state发生变化的时候自动执行

store.subscribe(() => {

console.log('state变化了', store.getState())

document.getElementById('count').innerText = store.getState().count

})

// 4. 通过store实例的dispatch函数提交action更改状态

const inBtn = document.getElementById('increment')

inBtn.addEventListener('click', () => {

// 增

store.dispatch({

type: 'INCREMENT'

})

})

const dBtn = document.getElementById('decrement')

dBtn.addEventListener('click', () => {

// 减

store.dispatch({

type: 'DECREMENT'

})

})

// 5. 通过store实例的getState方法获取最新状态更新到视图中

</script>

Redux 数据流架构

Redux 的数据流向清晰,从 stateaction,再到 reducer,最后回到新的 state

Redux 与 React 环境准备

虽然 Redux 可以独立于 React 使用,但通常我们会将其与 React 结合,利用 react-redux 库来连接 Redux 和 React 组件。

配套工具

Redux Toolkit (RTK):官方推荐的编写 Redux 逻辑的方式,简化代码。react-redux:连接 Redux 和 React 的桥梁。

配置基础环境

使用 Create React App (CRA) 创建项目,并安装必要的依赖。

npx create-react-app react-redux

npm i @reduxjs/toolkit react-redux

npm run start

Redux 与 React 实现计数器

使用 Redux Toolkit 创建 Store

利用 createSlice API 简化 slice 的创建,包括初始状态、reducers 和 actions。

//store/modules/conterStore.js

import { createSlice } from '@reduxjs/toolkit'

const counterStore = createSlice({

// 模块名称独一无二

name: 'counter',

// 初始化数据state

initialState: {

count: 1

},

// 修改数据的同步方法

reducers: {

increment (state) {

state.count++

},

decrement(state){

state.count--

}

}

})

// 解构出actionCreater函数

const { increment, decrement } = counterStore.actions

// 获取reducer函数

const counterReducer = counterStore.reducer

// 以按需导出的方式导出actionCreater函数和reducer函数

export { increment, decrement }

// 以默认导出的方式导出reducer函数

export default counterReducer

为 React 注入 Store

使用 Provider 组件将 store 传递给 React 应用,建立连接。

// 项目的src/index.js中

import React from 'react'

import ReactDOM from 'react-dom/client'

import App from './App'

// 导入store

import store from './store'

// 导入store提供组件Provider

import { Provider } from 'react-redux'

ReactDOM.createRoot(document.getElementById('root')).render(

// 提供store数据

<Provider store={store}>

<App />

</Provider>

)

React 组件使用 Store 数据

使用 useSelector 钩子从 store 中读取数据,使用 useDispatch 钩子分发 actions。

//app.js

import './App.css';

import { useDispatch, useSelector } from 'react-redux';

function App() {

const count = useSelector(state => state.counter.count);

return(

<div className="App">code>

{ count}

</div>

);

}

export default App;

React 组件修改 Store 中的数据

使用 useDispatch 钩子生成提交 action 对象的 dispatch 函数。

//App.js

import './App.css';

import { useDispatch, useSelector } from 'react-redux';

import { increment, decrement } from './store/modules/counterStore';

function App() {

const count = useSelector(state => state.counter.count);

const dispatch = useDispatch();

return(

<div className="App">code>

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

{ count}

<button onClick={ () => dispatch(decrement())}>Decrement</button>

</div>

);

}

export default App;

Redux 与 React 提交 Action 传参

在 action 创建函数中添加参数,允许在 dispatch 时传递额外的数据。

//conterStore.js

import { createSlice } from '@reduxjs/toolkit'

const counterStore = createSlice({

// 模块名称独一无二

name: 'counter',

// 初始化数据state

initialState: {

count: 0

},

// 修改数据的同步方法

reducers: {

increment (state) {

state.count++

},

decrement(state){

state.count--

},

addToNum(state, action){

state.count += action.payload

}

}

})

// 解构出actionCreater函数

const { increment, decrement, addToNum } = counterStore.actions

// 获取reducer函数

const reducer = counterStore.reducer

// 以按需导出的方式导出actionCreater函数和reducer函数

export { increment, decrement, addToNum }

// 以默认导出的方式导出reducer函数

export default reducer

//App.js

import './App.css';

import { useDispatch, useSelector } from 'react-redux';

import { increment, decrement, addToNum } from './store/modules/counterStore';

function App() {

const count = useSelector(state => state.counter.count);

const dispatch = useDispatch();

return (

<div className="App">code>

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

{ count}

<button onClick={ () => dispatch(decrement())}>Decrement</button>

<button onClick={ () => dispatch(addToNum(10))}>Add 10</button>

<button onClick={ () => dispatch(addToNum(20))}>Add 20</button>

</div>

);

}

export default App;

Redux 异步 Action 处理

封装异步逻辑,如 API 请求,并在获取数据后 dispatch 同步 action 更新状态。

//store/modules/channelStore.js

import { createSlice } from '@reduxjs/toolkit'

import axios from 'axios'

const channelStore = createSlice({

name: 'channel',

initialState: {

channelList: []

},

reducers: {

setChannelList (state, action) {

state.channelList = action.payload

}

}

})

// 创建异步

const { setChannelList } = channelStore.actions

const url = 'http://geek.itheima.net/v1_0/channels'

// 封装一个函数 在函数中return一个新函数 在新函数中封装异步

// 得到数据之后通过dispatch函数 触发修改

const fetchChannelList = () => {

return async (dispatch) => {

const res = await axios.get(url)

dispatch(setChannelList(res.data.data.channels))

}

}

export { fetchChannelList }

const channelReducer = channelStore.reducer

export default channelReducer

//store/index.js

import { configureStore } from '@reduxjs/toolkit'

import counterReducer from './modules/counterStore'

import channelReducer from './modules/channelStore'

const store = configureStore({

reducer: {

counter: counterReducer,

channel: channelReducer

}

})

export default store

//App.js

import './App.css';

import { useDispatch, useSelector } from 'react-redux';

import { increment, decrement, addToNum } from './store/modules/counterStore';

import { fetchChannelList } from './store/modules/channelStore';

import { useEffect } from 'react';

function App() {

const count = useSelector(state => state.counter.count);

const {channelList} = useSelector(state => state.channel);

const dispatch = useDispatch();

//使用useEffect触发异步请求执行

useEffect(() => {

dispatch(fetchChannelList());

}, [dispatch]);

return (

<div className="App">code>

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

{count}

<button onClick={() => dispatch(decrement())}>Decrement</button>

<button onClick={() => dispatch(addToNum(10))}>Add 10</button>

<button onClick={() => dispatch(addToNum(20))}>Add 20</button>

<ul>

{channelList.map(task => <li key={task.id}>{task.name}</li>)}

</ul>

</div>

);

}

export default App;

Redux 调试 - DevTools

使用 Redux DevTools 进行状态管理和 action 的调试,提供实时的 state 展示和 action 追踪。

结语

Redux 提供了一种强大且可预测的方式来管理应用的状态。通过本教程,你已经了解了 Redux 的基本概念、如何在 React 中使用 Redux,以及如何处理异步操作和调试。希望这能帮助你更好地构建和管理复杂的前端应用状态。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。