redux
React只是DOM的一个抽象层
Web应用是一个状态机,视图与状态是一一对应的
所有的状态,保存在一个对象里面(唯一数据源)
需要使用redux的项目
- 用户的使用方式复杂
- 不同身份的用户有不同的使用方式(比如普通用户和管理员)
- 多个用户之间可以协作
- 与服务器大量交互,或者使用了WebSocket
- View要从多个来源获取数据
从组件层面考虑,什么样子的需要redux:
- 某个组件的状态,需要共享
- 某个状态需要在任何地方都可以拿到
- 一个组件需要改变全局状态
- 一个组件需要改变另一个组件的状态
redux有四个组成部分
store:用来存储数据
reducer:真正的来管理数据
actionCreators:创建action,交由reducer处理
view:用来使用数据
redux的流程
1)store通过reducer创建了初始状态
2)view通过store.getState()获取到了store中保存的state挂载在了自己的状态上
3)用户产生了操作,调用了actions 的方法
4)actions的方法被调用,创建了带有标示性信息的action
5)actions内部通过调用store.dispatch方法将标志性的action发送到了reducer中
6)reducer接收到action并根据标识信息判断之后返回了新的state
7)store的state被reducer更改为新state的时候,store.subscribe方法里的回调函数会执行,此时就可以通知view去重新获取state
例如创建如下案例
store通过reducer创建了初始状态,在reducer中定义一个数组
reducer.js
let state = {
list: [
{ id: 1, title: "星期一", isFinished: true },
{ id: 2, title: "星期二", isFinished: false }
]
}
const reducer = (prevState = state, action) => {
//让上一条数据默认为state
let newState = { ...prevState }
return newState
}
view通过store.getState()获取到了store中保存的state挂载在了自己的状态上
在TodoContent组件中展示数据
const LiItem = props => {
return (
<li key={props.item.id} style={{textDecoration:props.item.isFinished?'line-through':'none'}}>
{props.item.title}
</li>
)
}
export default class TodoContent extends Component {
constructor() {
super()
//声明一条数据
this.state = {
list: []
}
}
setList = () => {
//从store的getState()方法中获取到list并更改state中的list数据
this.setState({
// Store对象包含所有数据。如果想得到某个时点的数据,就要对 Store 生成快照。当前时刻的 State,可以通过store.getState()拿到。
list: store.getState().list
})
}
componentDidMount() {
this.setList()
//Store 允许使用store.subscribe方法设置监听函数,一旦 State 发生变化,就自动执行这个函数。当state的数据改变时,就去执行setList,由此state的数据也会改变,render也会重新渲染
store.subscribe(() => {
this.setList()
})
}
renderList = () => {
let {list} =this.state
return list.map(item => {
return <LiItem key={item.id} item={item} />
})
}
render() {
return (
<ul>
{
this.renderList()
}
</ul>
)
}
}
当input框输入文本时,按下键盘下的Enter,列表会增加一条
也就是当用户产生了操作,调用了actions 的方法
组件TodoInput
import actionCreators from "../../store/actionCreators"
export default class TodoInput extends Component {
handleKey=e=>{
if(e.keyCode==13){
// 当按下Enter键时,触发actionCreators下的addNewTode
actionCreators.addNewTode(e.target.value)
e.target.value=""
}
}
render() {
return (
<input placeholder="请输入内容" onKeyUp={this.handleKey}/>
)
}
}
actions的方法被调用,创建了带有标示性信息的action
actions内部通过调用store.dispatch方法将标志性的action发送到了reducer中
actionCreators.js
const actionCreators = {
addNewTodo(title){
//需要定义一个具有特殊标识的action对象
let action = {
type:ADD_NEW_TODO,
title
}
//需要将action对象派发给reducer
store.dispatch(action)
}
}
export default actionCreators
reducer接收到action并根据标识信息判断之后返回了新的state,store.subscribe方法里的回调函数会执行,此时就可以通知view去重新获取state
reducer.js
const reducer = (prevState = state, action) => {
let newState = { ...prevState }
return newState
}