React16_4整理-Redux上阶
# 前言
前面说到React
中 数据与视图分离
,但是JS逻辑和视图
是混在一起
的,其实可以通过设计来进行拆分。
还有无状态组件以及React中redux的一些第三方插件,比如redux-thunk、redux-saga。
thunk推迟执行,saga用到了生成器,。这些第三方插件都是为了让状态管理更加的轻松,从而降低心智压力。
# UI 组件与容器组件的拆分
UI 组件也叫傻瓜组件
,容器组件也叫聪明组件
。
UI 组件负责页面的渲染,容器组件负责页面的逻辑。
# 代理示例
UI 组件-TodoListUI
import React,{ Component } from 'react';
import { Input ,Button, List } from 'antd';
import '../node_modules/antd/dist/antd.css';
class TodoListUI extends Component {
render() {
return(
<div style = {{margin: '10px 0px 0px 10px',width: "500px"}}>
<div>
<Input placeholder = "请输入内容"
value = {this.props.inputValue}
onChange = {this.props.handleChange}
style = {{marginRight: '10px',width: "350px"}}
/>
<Button type = "primary"
style = {{width: "80px"}}
onClick = {this.props.handleClick}
>提交
</Button>
<List
bordered
dataSource = {this.props.list}
style = {{width: '350px',marginTop: '10px'}}
renderItem = {(item, index) => (<List.Item onClick = {(index) => {
this.props.handleRemoveItem(index);
}}>{item}</List.Item>)}
/>
</div>
</div>
)
}
}
export default TodoListUI;
容器组件-TodoList
import React,{ Component } from 'react';
import TodoListUI from './TodoListUI'
//import store from './store/index.js'
import store from './store';
// import {CHANGEINPUTVALUE,ADDLISTITEM,REMOVEITEM} from './store/actionTypes'
import {getInputeChangeAction, addListItemAction, removeItemAction} from './store/actionCreators';
class TodoList extends Component {
constructor (props) {
super(props);
console.log(store.getState());
this.state = store.getState();
this.handleChange = this.handleChange.bind(this);
this.handleStoreChange = this.handleStoreChange.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleRemoveItem = this.handleRemoveItem.bind(this);
// 监听 store中的状态改变
store.subscribe(this.handleStoreChange);
}
render () {
return (
<TodoListUI
inputValue = {this.state.inputValue}
handleChange = {this.handleChange}
handleClick = {this.handleClick}
handleRemoveItem = {this.handleRemoveItem}
/>
)
}
handleChange (e) {
const action = getInputeChangeAction(e.target.value)
store.dispatch(action);
}
handleStoreChange () {
this.setState(store.getState());
}
handleClick () {
const action = addListItemAction();
store.dispatch(action);
}
handleRemoveItem (index) {
const action = removeItemAction(index);
store.dispatch(action);
}
}
export default TodoList;
# React 中无状态组件
以函数定义的方式定义一个组件,可以传递一个 props 来获取传递过来的数据。
当一个组件只有 render 函数的时候,这个时候就可以使用一个无状态的组件替换这个组件。
import React, { Component } from 'react';
import { Input, Button, List } from 'antd';
import '../node_modules/antd/dist/antd.css';
// 无状态组件的写法
const TodoListUI2 = (props) => {
return(
<div style = {{margin: '10px 0px 0px 10px',width: "500px"}}>
<div>
<Input placeholder = "请输入内容"
value = {props.inputValue}
onChange = {props.handleChange}
style = {{marginRight: '10px', width: "350px"}}
/>
<Button type = "primary"
style = {{width: "80px"}}
onClick = {props.handleClick}
>提交</Button>
<List
bordered
dataSource = {props.list}
style = {{width: '350px', marginTop: '10px'}}
renderItem = {
(item,index) => (
<List.Item onClick = {() =>{
props.handleRemoveItem(index);
}}>{item}</List.Item>)
}
/>
</div>
</div>
)
}
export default TodoListUI2;
无状态的组件性能比较高,因为它本身就是一个函数。而有状态的组件继承自 React.Component,有一套生命周期,所以要去执行这一套生命周期,所以性能肯定没有只需要执行一个函数的组件好。
无状态组件一般用于 UI 组件中。
# Redux 中发送异步请求获取数据
在 ComponentDidMount 中发送 axios 异步请求,然后初始化状态。
# 使用 Redux-thunk 中间件进行 ajax 请求发送
首先安装 Redux-thunk
使用命令 yarn add redux-thunk
或者 npm install --save redux-thunk
引入 redux
的createStore、applyMiddleware、compose
然后再引入 redux-thunk
,最后创建store
的时候将中转一下thunk
后的enhancer
作为第二个参数传递进去,之所以使用这种方式,是为了可以使用多
个中间件
。
import {createStore, applyMiddleware, compose} from 'redux';
import thunk from 'redux-thunk';
import reducer from '/reducer.js';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : conpose;
// 做一个中转
const enhancer = composeEnhancers(
applyMiddleware(...[thunk])
)
const store=createStore(reducer, enhancer)
export default store;
使用redux-thunk
,可以让store.dispatch
中可以传递
一个函数
而不
是仅仅
只能是一个对象
,所以说redux-thunk
扩展了store.dispatch
的功能,redux-thunx
就是rudux
的插件。
使用redux-thunk
之后,你使用store.dispatch
,你如果传递一个函数进去,那么它会调用这个函数,并且把store.dispatch
传递进去。
如果你传递的是一个对象,那么它会去调用reducer
这个函数,也就是reducer.js
导出的那个函数。
通过那个函数来进行state
的处理和newState
的返回,最后通过store
改变state
。
在使用redux
创建store
的时候会使用到中间件,这是 redux 的中间件。
# 到底什么是 Redux 中间件?
就是对Redux
中store的dispatch
方法做
了一个升级
。
如redux-thunk
对dispatch
方法做
了一个升级
,默认
的 dispatch只
能传递
一个对象
,然后将这个对象和当前全局的state
传递给reducer
这个方法并调用
,最后获取reducer
方法中的返回值来修改state
。
升级后的dispatch支持接收一个函数
,这个函数
会在dispatch
方法体中被执行
,并且会在执行
的时
候传递store.dispatch
进去,直到
你传递
的是一个对象
,之后
就会像默认的dispatch
那样,走完这套流程后最终修改state
。
# 除了 redux-thunk 这样的中间件之外还有其它的中间件
如 redux-loger
:用来记录每次 action 的日志
如 redux-saga
:它也是解决Redux
中异步问题的中间件,它不同于 redux-thunk 将异步请求放到 action 中进行,它是把异步操作单独的放到一个文件中进行管理
# Redux-sage 中间件的使用
Redux中间件
指的是 action
和store
的中间
,也就是dispatch
这个函数,对它进行升级
,只有redux
中才有action
和store
的概念,将异步代码放到action
中去做,有利于自动化测试
,和代码
的拆分管理
。
使用命令安装 Redux-saga:npm install redux-saga --save
或者yarn add redux-saga
使用Redux-saga
:先从Redux-saga
中引入 createSagaMiddleware
执行createSagaMiddleware()
之后传入 saga
中间件的的对象
import {createStore, applyMiddleware, compose} from 'redux';
import createSagaMiddleware from 'redux-saga';
import reducer from '/reducer.js';
const sagaMiddlware = createSagaMiddleware();
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : conpose;
// 做一个中转
const enhancer = composeEnhancers(
applyMiddleware(...[sagaMiddlware])
)
const store = createStore(reducer, enhancer)
export default store;
compose
的使用: 你可以在里面传递很多
的方法
,传递的方法会依次被执行
。
redux-saga
在处理非常大型项目时优于redux-thunk
redux-thunk
没有什么 api,所以很简单
,redux-saga
有很多 api 所以相对复杂一点
。
# React-redux
是 React 第三方模块儿,可以更加方便的使用redux
。
使用命令来进行安装:yarn add react-redux
。
react-redux 中提供的 API
Provider
组件
import { Provider } from 'react-redux';
import store from './store';
<!-- Provider表示提供器,store = store表示连接store,
这样一来,里面的组件都可以直接使用连接的store了
-->
const App=(
<Provider store = {store}>
<TodoList />
</Provider>
)
ReactDOM.render(App, document.getElementById("root"));
connect
方法
import {connect} from 'react-redux'
class TodoList extends Component {
}
// 这个函数表示将store中state映射到当前的props中去
const mapStateToPorps = (state) => {
return {
inputValue:state.inputValue
}
}
// 表示将store.dispatch方法挂载到props中的函数成员中,
// 然后就可以直接在函数中调用dispatch了
const mapDispatchToProps = (dispatch) => {
return {
changeInputValue(e){
const action = {
type: 'changeInputValue',
value: e.target.value
}
dispatch(action);
}
}
}
// connenct 表示连接Provider中的store
// mapStateToPorps 获取值 ,mapDispatchToProps 设置值,TodoList 被连接的组件
// 最终返回一个容器组件
export default connect(mapStateToPorps, mapDispatchToProps)(TodoList)
# React-redux 的使用
connect 方法返回的结果实际上是一个容器组件,因为它里面包含了 数据的传递和方法传递
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {inputChange, clickSubmit, clickRemoveItem} from './store/actionCreators.js'
// 这是一个无状态的UI组件
const TodoList = (props) => {
const {handleInputChange, handleClickSubmit, handleClickRemoveItem, list, inputValue} = props;
return(
<div>
<input onChange = {handleInputChange.bind(this)} type = "text" value = {inputValue}/>
<button onClick = {handleClickSubmit.bind(this)}>提交</button>
<ul>
{
list.map((item, index) => {
return (
<li onClick = {handleClickRemoveItem.bind(this, index)} key = {index}>{item}</li>
)
})
}
</ul>
</div>
)
}
// 将store.state映射到this.props中
const mapStateToPorps= (state) => {
return {
inputValue: state.inputValue,
list: state.list
}
}
// 将store.dispatch 传递到 所有的props里的自定义函数中
const mapDispatchToProps = (dispatch) => {
return {
handleInputChange (e) {
const action = inputChange(e.target.value);
dispatch(action);
},
handleClickSubmit () {
const action = clickSubmit();
dispatch(action);
},
handleClickRemoveItem (index) {
const action = clickRemoveItem(index);
dispatch(action);
}
}
}
// 这里返回一个容器组件
export default connect(mapStateToPorps, mapDispatchToProps)(TodoList)
# 总结
在redux中有很多状态管理的第三方插件(中间件),比如react-thunk、react-saga,这些中间件都是通过升级dispatch这个方法,来实现更加便捷更加优秀的状态管理机制。
react的react-redux更是加入了对redux的简易封装,更好的让你的代码组织方式更加优雅,从而提高开发效率,降低心智压力。
Provider表示提供器,store = store表示连接store,这样一来,里面的组件都可以直接使用连接的store。 connenct 表示连接Provider中的store
mapStateToPorps 从state中获取值,mapDispatchToProps 设置state值,TodoList 被连接的组件。
mapStateToPorps:这个函数表示将store中state映射到当前的props中去
mapDispatchToProps:表示将store.dispatch方法挂载到props中的函数成员中,然后就可以直接在函数中调用dispatch了。