之前学了Vue,最近在学React,其实上手比较快的,感觉框架都有相通的地方。刚刚学了Mobx和Redux两种状态管理工具,感觉分别跟vuex和pinia有点像。
前置知识
- JSX语法
- 列表渲染
- 变量动态绑定
- 状态管理工具
- Redux
- Mobx
状态管理
Mobx
使用更方便,使用class定义store,就是要注意在导出使用的组件时记得使用observer()监听组件,才能更新渲染。
基本使用
- 定义store
- 定义数据状态state
- 在构造器中实现数据响应式处理 makeAutoObservble
- 定义修改数据的函数action
- 实例化store并导出
import { makeAutoObservable } from 'mobx'
class CounterStore {
count = 0 // 定义数据
constructor() {
makeAutoObservable(this) // 响应式处理
}
// 定义修改数据的方法
addCount = () => {
this.count++
}
}
const counter = new CounterStore()
export default counter
- React使用store
- 在组件中导入counterStore实例对象
- 在组件中使用counterStore实例对象中的数据
- 通过事件调用修改数据的方法修改store中的数据
- 让组件响应数据变化
// 导入counterStore
import counterStore from './store'
// 导入observer方法
import { observer } from 'mobx-react-lite'
function App() {
return (
<div className="App">
<button onClick={() => counterStore.addCount()}>
{counterStore.count}
</button>
</div>
)
}
// 包裹组件让视图响应数据变化
export default observer(App)
Redux
将所有的数据存储在一个单一的存储中,以便在整个应用程序中共享和访问。
基本使用
- 创建couterStore
- 使用toolkit的createSlice方法创建一个独立的子模块
- 使用configureStore语法组合子模块
子模块:
import { createSlice } from '@reduxjs/toolkit'
const counter = createSlice({
// 模块名称独一无二
name: 'counter',
// 初始数据
initialState: {
count: 1
},
// 修改数据的同步方法
reducers: {
add (state) {
state.count++
}
}
})
const { add } = counter.actions
const counterReducer = counter.reducer
// 导出修改数据的函数
export { add }
// 导出reducer
export default counterReducer
组合子模块:
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterStore'
export default configureStore({
reducer: {
// 注册子模块
counter: counterReducer
}
})
- 为React提供Redux Store
在入口文件中,渲染根组件的位置通过Provider提供store数据
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>
)
- 组件中使用store中的数据
组件使用store中的数据需要借助一个hook方法,叫做useSelector
useSelector(state => state.模块名) 方法的返回值为一个对象,对象中包含store子模块中的所有数据
import { useSelector } from 'react-redux'
function App () {
// 使用数据
const { count } = useSelector(state => state.counter)
return (
<div className="App">
{count}
<button onClick={clickHandler}>+</button>
</div>
)
}
export default App
- 组件修改store中的数据
- 使用counterStore模块中导出的add方法创建action对象
- 通过dispatch函数以action作为参数传入完成数据更新
import { useSelector, useDispatch } from 'react-redux'
import { add } from './store/counterStore'
function App () {
// 使用数据
const { count } = useSelector(state => state.counter)
// 修改数据
const dispatch = useDispatch()
const clickHandler = () => {
// 1. 生成action对象
const action = add()
// 2. 提交action进行数据更新
dispatch(action)
}
return (
<div className="App">
{count}
<button onClick={clickHandler}>+</button>
</div>
)
}
export default App
- 组件修改数据并传参
- 通过action的payload属性接收参数
import { createSlice } from "@reduxjs/toolkit"
const counterStore = createSlice({
name: 'counter', // 独一无二不重复的名字语义化
// 定义初始化的数据
initialState: {
taskList: ['react']
},
reducers: {
// action为一个对象 对象中有一个固定的属性叫做payload 为传递过来的参数
addTaskList (state, action) {
state.taskList.push(action.payload)
}
}
})
// 生成修改数据的方法导出
const { addTaskList } = counterStore.actions
export { addTaskList }
// 生成reducer 导出 供index.js做组合模块
const counterReducer = counterStore.reducer
export default counterReducer
- dispatch的时候传入实参
<button onClick={() => dispatch(addTaskList('vue'))}>addList</button>
实现功能
- 渲染列表
通过列表渲染获取的list数据,根据每个任务不同的isDone状态决定class,使用不同的css样式。
<ul className="todo-list">
{
list.map(item=>(
<li className={item.isDone ? 'todo completed' : 'todo'} key={item.id}>
<div className="view">
<input className="toggle" type="checkbox" value={item.isDone} checked={item.isDone} onClick={()=>{dispatch(changeTask(item.id))}}/>
<label>{item.name}</label>
<button className="destroy" onClick={()=>{dispatch(delTask(item.id))}}></button>
</div>
</li>
</ul>
其中不同功能的方法由使用的不同状态管理工具决定。
- 获取任务列表
Mobx:const {taskStore}=useStore()
Redux:const {list}=useSelector(state=>state.tasks)
- 定义增删改查方法
Mobx:
addTask(name) {
this.list.push({
id: uuid(),
name,
isDone: false
})
}
changeIsDone(id) {
const task = this.list.find(item => item.id === id)
task.isDone = !task.isDone
}
deleteTask(id) {
this.list = this.list.filter(item => item.id !== id)
}
toggleAll() {
const isDone = this.list.every(item => item.isDone)
this.list.forEach(item => item.isDone = !isDone)
}
Redux:
// 修改数据的同步方法
reducers: {
// 添加任务
addTask(state, action) {
const newTask={
id:uuid(),
name:action.payload,
isDone:false
}
state.list.push(newTask)
},
// 删除任务
delTask(state, action) {
const id = action.payload
const index = state.list.findIndex(item => item.id === id)
state.list.splice(index, 1)
},
// 修改任务状态
changeTask(state, action) {
const id = action.payload
const task = state.list.find(item => item.id === id)
task.isDone = !task.isDone
},
toggleAll(state) {
const isDone = state.list.every(item => item.isDone)
state.list.forEach(item => item.isDone = !isDone)
},
}