Redux详解
Redux介绍
Redux 是 JavaScript 应用的状态容器,提供可预测的状态管理。
在Redux中有3个原则
-
单一数据源
整个应用的
State
被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个Stroe
中。 -
State 是只读的
唯一改变
State
的方法就是触发Actions
,Actions
是一个用于描述已发生事件的普通对象。 -
使用纯函数来执行修改
为了描述
Actions
如何改变 State tree ,你需要编写Reducers
。
如下图所示,在Redux中,有一个全局状态存储器Store
,只有Actions
才能去进行修改Store
中的数据,其更改数据这一过程,即store.dispatch(action)
就是为Reducers
。当Actions
修改完Store
中的数据后,Store
会通知对应页面其数据发送改变。
Redux有什么作用
得益于react是单项数据流的关系,在react框架中要统筹全局数据就显得较为繁琐,需要通过父子间的组件传递/或者是Context才能进行跨组件交流,但在react里,context是个反模式的东西,不同于redux等的细粒度响应式更新,context的值一旦变化,所有依赖该context的组件全部都会force update
,因为context API并不能细粒度地分析某个组件依赖了context里的哪个属性,并且它可以穿透React.memo
和shouldComponentUpdate
的对比,把所有涉事组件强制刷新。
Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。
如何在React中使用Redux
React中
使用的是react-redux
这个三方包
这里借用下大佬绘制的流程图,大致流程如下
react-redux中的connect方法将store上的getState 和 dispatch 包装成组件的props。
如何使用React-redux
举个todoList的栗子
在需要共享数据的主入口,先引入redux
和react-redux
,再引入 createStore
来创建组件共享的数据,这个是 redux
中提供的一个方法,我们直接引入,并将主入口文件用Provider
包裹一下。
import React, { Component } from 'react';
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import reducer from './redux/reducer/index'
import AddItemPage from './components/index'
const store = createStore(reducer) //使用createStore创建个store
export default class App extends Component {
render() {
return (<Provider store={store}> //todoList共享store
<AddItemPage/> //todoList页面
</Provider>)
}
}
然后去定义action
和reducer
的初始状态,因为在reducer中已经设置了state的初始值为[]
,故不作定义state
reducer的
import { combineReducers } from 'redux'
const addItem = (state = [], action) => {
switch (action.type) {
case 'ADD_ITEM':
return [
...state,
{
id: action.id,
text: action.text,
isDelete: false
}
]
case 'DELETE_ITEM':
let newState = [...state]
console.log(newState)
action.id.map(item=>{
newState.splice(item.id,1)
})
return newState
default:
return state
}
}
export default combineReducers({
addItem
})
action
let nextItemId = 0
export const addTodo = text => ({
type: 'ADD_ITEM',
id: nextItemId++,
text
})
export const deleteItem = id => ({
type: 'DELETE_ITEM',
id
})
然后再模块中将定义的action
以及reducer
返回的state
链接到模块中
import React, { Component } from 'react';
import { connect } from 'react-redux'
import { addTodo,deleteItem } from '../redux/action'
import ItemList from './itemList'
class AddItem extends Component {
render() {
const { addItem,doAdd,doDelete } = this.props
return <>
<div>
<form onSubmit={e => {
e.preventDefault()
if (!this.input.value.trim()) {
return
}
doAdd(this.input.value)
// this.props.dispatch(addTodo(this.input.value))
this.input.value = ''
}}>
<input ref={node => this.input = node} />
<button type="submit">
添加
</button>
<button type="button" onClick={(e)=>{
let arr = []
const checkbox = document.getElementsByName('itemId').forEach(item=> {
if(item.checked) arr.push(item.value)
})
doDelete(arr)
// this.props.dispatch(deleteItem(arr))
}}>
删除
</button>
</form>
</div>
<ItemList addItem={addItem}/>
</>
}
}
const mapStateToProps = state => {return ({...state})}
const mapDispatchToProps = dispatch => ({
doAdd:(value)=>dispatch(addTodo(value)),
doDelete:(arr)=>dispatch(deleteItem(arr))
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(AddItem)
import React, { Component } from 'react';
class itemList extends Component {
render() {
return <>
{
this.props.addItem.map(item=>{
return <div key={item.id} {...item}>
<input type='checkbox' name='itemId' value={item?.id}/>
<li
style={{
textDecoration: item?.completed ? 'line-through' : 'none'
}}
>
{item?.text}
</li>
</div>
})
}
</>;
}
}
export default itemList
即可,
可以看到输入123,点击添加的时候触发了ADD_ITEM的操作
点击删除的时候触发了DELETE_ITEM操作