Redux
一、Redux是什么
官方解释:redux 是 js 应用的可预测状态的容器。 可以理解为全局数据状态管理工具(状态管理机),用来做组件通信等。
二、Redux 流向
1、redux的组成
store:用来存储数据
reducer:真正的来管理数据
actionCreators:创建action,交由reducer处理
view:用来使用数据,在这里,一般用react组件来充分
2、流程
a、创建store
从redux工具中取出createStore去生成一个store
import { createStore } from 'redux';
import reducer from "./reducer"
//创建了store仓库,借助外部传入的reducer纯函数
const store = createStore(reducer)
export default store
b、创建一个reducer,然后将其传入到createStore中辅助store的创建
注:ruducer是一个纯函数,接收当前状态和action,返回一个状态,返回什么,store的状态就是什么,需要注意的是,不能直接操作当前状态,而是需要返回一个新的状态。
想要给store创建默认状态其实就是给reducer一个参数创建默认值。
let state = { //规定了redux的一些初始化的共享状态
list:[
{id:1,title:"今天星期一,新的一天背代码"},
{id:2,title:"明天星期二,新的一天背代码"}
]
}
//Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。
//Reducer是一个纯函数。也就是说,只要是同样的输入,必定得到同样的输出
//注意:不能对之前的状态进行任何的更改,内部只能是同步的操作! 不能有 Math.random() new Date()
//内部要求 状态与视图是一一对应的,只要外部传入的状态不变,所对应的的视图也不应该发生改变!
const reducer = (prevState = state,action)=>{
let newState = {...prevState} //newState={list:[]}
return newState;
}
export default reducer;
c、组件通过调用store.getState方法来使用store的数据。
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import store from "./store"
//reducer函数返回什么内容,store.getState()就可以获取什么内容
// console.log("store===>",store.getState())
ReactDOM.render(
<App />,
document.getElementById('root')
import React, { Component } from 'react'
import store from "../../store"
export default class TodoContent extends Component {
constructor(){
super()
this.state = {
list:[]
}
}
componentDidMount(){
//如何获取reducer的返回结果
this.setState({
list:store.getState().list
})
}
render() {
let {list} = this.state;
return (
<ul>
{
list.map(item=>{
return <li key={item.id}>{item.title}</li>
})
}
</ul>
)
}
d、组件产生用户操作,调用actionCreator的方法创建一个action,利用store.dispathch方法传递给reducer
import React, { Component } from 'react'
import actionCreators from "../../store/actionCreators"
export default class TodoInput extends Component {
handleKeyUp = e=>{
if(e.keyCode === 13){
//目标:需要将redux的list再去添加一项。更改redux状态,必须通过派发action才可以
actionCreators.addNewTodo(e.target.value)
e.target.value = ""
}
}
render() {
return (
<input onKeyUp={this.handleKeyUp} placeholder="请输入内容..."/>
)
}
}
e、reducer对action上的标志性信息做出判断后对新状态进行管理,然后返回新状态,这个时候store的数据就会发生改变 reducer返回什么状态,store.getState就可以获取什么状态。
import store from "./index"
const actionCreators = {
addNewTodo(title){ //actionCretors or action区别?
//需要定义一个具有特殊标识的action对象
let action = {
type:"addNewTodo",
title
}
//需要将action对象派发给reducer
store.dispatch(action)
}
}
export default actionCreators
let state = {
list:[
{id:1,title:"今天星期一,新的一天背代码"},
{id:2,title:"明天星期二,新的一天背代码"}
]
}
//Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。
//Reducer是一个纯函数。也就是说,只要是同样的输入,必定得到同样的输出
//注意:不能对之前的状态进行任何的更改,内部只能是同步的操作! 不能有 Math.random() new Date()
//内部要求 状态与视图是一一对应的,只要外部传入的状态不变,所对应的的视图也不应该发生改变!
const reducer = (prevState = state,action)=>{
let newState = {...prevState} //newState={list:[]}
switch (action.type) {
case "addNewTodo":
newState.list.push({id:handler.getId(newState.list),title:action.title})
break;
default:
break;
}
return newState;
}
const handler = {
getId(list){
list = list.slice()
if(list.length ===0) return 1;
return list.sort((a,b)=>{ //list=[{id:3},{id:2}]
return b.id - a.id
})[0].id+1
}
}
export default reducer;
f、我们可以在组件中,利用store.subscribe方法去订阅数据的变化,也就是可以传入一个函数,当数据变化的时候,传入的函数会执行,在这个函数中让组件去获取最新的状态。
componentDidMount(){
//如何获取reducer的返回结果
this.setState({
list:store.getState().list
})
//当redux的状态发生改变了,组件默认是监听不到的
//订阅状态改变,当redux状态发生改变了,内部回调仍然执行
store.subscribe(()=>{
this.setState({
list:store.getState().list
})
})
}
三、Redux的特性
1、单向性
单向数据流其实并不是redux的特性,而是react本身的思想
2、唯一性
指的是应用的数据都会集中存储在一个地方,这个数据Store就像一个池子,任何组件都可以通过固定的管道来传输或者获取这个池子里面的数据
3、时间旅行
这个“时间旅行”另外的意思是可预测(predictable),即容易理解的代码。在redux里,任何一个数据都有状态。一个用户操作或者程序需要去修改数据,都必须触发Action,这时在redux看来,其实数据是从一个状态,变化成另一个状态。这么一来,数据就变得可预测,可以知道数据的前置状态(prev state)和后置状态(next state)分别是什么,如果在这里加上单元测试,也是极其容易的一件事情。
四、优点与缺点
优点:
1、Redux把流程规范了,统一渲染根节点虽然对代码管理上规范了一些,只要有需要显示数据的组件,当相关数据更新时都会自动进行更新。
2、减少手动编码量,提高编码效率。
3、Redux 会更加注重数据的单一流向性,所有的 Component
缺点:
学习成本比较高,严格的函数式思维比较难以转化,刚开始接触会觉得过程非常繁琐。
五、使用场景
1、简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。
- 用户的使用方式非常简单
- 用户之间没有协作
- 不需要与服务器大量交互,也没有使用 WebSocket
- 视图层(View)只从单一来源获取数据
2、需要使用redux的项目: - 用户的使用方式复杂
- 不同身份的用户有不同的使用方式(比如普通用户和管理员)
- 多个用户之间可以协作
- 与服务器大量交互,或者使用了WebSocket
- View要从多个来源获取数据
3、从组件层面考虑,什么样子的需要redux: - 某个组件的状态,需要共享
- 某个状态需要在任何地方都可以拿到
- 一个组件需要改变全局状态
- 一个组件需要改变另一个组件的状态