Javaer的前端之路---Redux

跟着鱼皮哥也做了三四个项目了,不知大家在写代码的时候,有没有一种对后端代码的亲切和对前端代码的无力感,因为我是头铁怪,即使前端一点也不懂,我也尽量跟着敲,那种感觉非常痛苦,所以为了在接下来的项目道路上不吃瘪,我决定开始拓展一下我的前端知识。因为鱼皮哥的项目都是Vue和React切换的,所以我也或多或少知道了他们之间的使用区别,最后我觉得,React的编码风格更适合我,于是正式开始了我的React学习之路,具体的学习路线是跟着黑马的Java程序员开发所必备的前端知识的视频和黑马Pink老师的最新React视频穿插学习,今天学习的内容是Redux


如果星球里看的不方便,也可以移步到我的博客:Redux的入门及其使用 | Adagio Blog (gitee.io)

Redux入门及其使用

什么是Redux


Redux是React最常用的集中状态管理工具,类似于Vue中的Pinia (Vuex),可以独立于框架运行

作用:通过集中管理的方式管理应用的状态


案例:通过Redux实现一个计数器

使用步骤(原生)


  1. 定义一个reducer函数(根据当前想要做的修改返回一个新的状态)
// 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
}
  1. 使用createStore方法传入reducer函数生成一个store实例对象
// 2. 使用reducer函数生成store实例
const store = Redux.createStore(reducer)
  1. 使用store实例的subscribe方法订阅数据的变化(数据一旦变化,可以得到通知)
// 3. 通过store实例的subscribe订阅数据变化
// 回调函数可以在每次state发生变化的时候自动执行
store.subscribe(() => {
console.log('state变化了', store.getState())
document.getElementById('count').innerText = store.getState().count
})
  1. 使用store实例的dispatch方法提交action对象触发数据变化(告诉reducer你想怎么改数据)
// 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'
})
})
  1. 使用store实例的getState方法获取最新的状态数据更新到视图中


具体逻辑


Redux把整个数据修改的流程分成了三个核心概念,分别是: state、action和reducer

  1. state-一个对象,存放着我们管理的数据状态
  2. action-一个对象,用来描述你想怎么改数据
  3. reducer-一个函数,更具action的描述生成一个新的state

个人从后端的角度理解,View可以理解为前端,Action可以理解为路径,Reducer理解为Controller,Store理解为数据库,然后整体的逻辑就是,View发起请求到Reducer,Reducer根据不同的Action找到对应的逻辑对数据进行处理,然后把处理过的数据入库(也就是修改Store里面的数据),然后修改完之后,View去查Store,就可以查到新的数据了


Redux和React的搭配

案例:通过Redux实现一个计数器

1.搭建React和Redux环境


  1. 创建React项目
npx create-react-app react-redux-pro
  1. 下载依赖
npm i @reduxjs/toolkit react-redux-pro
  1. 这里具体的依赖有两个,一个@reduxjs/toolkit,用于对redux的方法进行封装,省略了很多复杂的代码;一个是@react-redux-pro,用于react组件和redux进行通信
  2. 创建目录结构,如图所示


2.编写代码


  1. 创建store对象,并且导出store对象的reducer和actions
import {createSlice} from "@reduxjs/toolkit"
const counterStore = createSlice({
name: "counter",
//初始值
initialState: {
count: 0
},
//修改状态的方法 同步方法 可直接修改
reducers: {
increment(state) {
state.count++
},
decrement(state) {
state.count--
}
}
}
)
//解构出actions
const {increment, decrement} = counterStore.actions
//获取reducer
const reducer = counterStore.reducer
//导出actions
export {increment, decrement}
//导出默认reducer
export default reducer
  1. 在index.js文件里进行reducer整合,可以把index.js当做状态管理中心,这里创建的store对象就是调用状态的入口(也就是在modules模块里可以有千千万万个类似counterStore.js的文件,然后需要把这些文件在index.js里注册,有多少个xxx.js,那么store的reducer里就可以写多少个)
import {configureStore} from "@reduxjs/toolkit";
//导入子模块reducer
import counterReducer from "./modules/counterStore"
const store = configureStore({
reducer: {
counter: counterReducer
}
})
//导出store对象
export default store
  1. 在前端程序的入口处(src里的index.js)注入store对象,代表这个前端程序可以共同使用和修改这个store的内容
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from "./store";
import {Provider} from "react-redux"

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
//需要用react-redux提供的Provider注入store
<Provider store={store}>
<App/>
</Provider>
</React.StrictMode>
);
reportWebVitals();
  1. 使用store,由上述代码可以看出我们用的是App组件,所以我们要去App组件里使用store
  2. 其中获取状态的hook用的是useSelector,state.counter里的counter要和步骤2的reducer里注册的一致
  3. 修改状态有且只有一种方法就是通过提交action,用的hook是useDispatch,action来自于步骤1中导出的方法,可以直接引入
import {useDispatch, useSelector} from "react-redux"
import {increment, decrement} from "./store/modules/counterStore";
function App() {
//获取状态
const {count} = useSelector(state => state.counter)
//创建dispatch对象
const dispatch = useDispatch();
//onClick方法里使用dispatch提交action来修改状态
return (
<div className="App">
<button onClick={() => {
dispatch(decrement())
}}>-
</button>
//使用状态
{count}
<button onClick={() => {
dispatch(increment())
}}>+
</button>
</div>
);
}
export default App;


3.总结


从我后端的角度来讲,这个有点像服务注册和服务发现的过程,modules里每个文件可以理解为一组状态(服务),然后需要把这组状态注册到其index.js里去(注册中心),在使用时我们要通过useSelector(state=>state.xxx)来获取这组状态(xxx可以理解服务名称,可以在注册中心里找到对应服务),然后我们需要用到这组状态对应方法的话,就要引入这组状态的方法,就可以使用了


4.其他


如果要给action添加参数并使用,要使用如下方式

在reducers里添加一个带参数的action方法,然后除了state,要加上一个action参数,然后从action的payload属性里可以获取到入参,并把这个方法导出

toNum(state,action){
state.count = action.payload
}

使用时只需要引入这个方法,然后传参就可以了,如下,其中10就是传入的参数,也就是上面的action.payload

<button onClick={() => {
dispatch(toNum(10))
}}>改成10
</button>


0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP