内容简介:我们以todolist中增加代办事项这个功能为例:为了开发规范一点我们要采取reducer的分片写法,即一个类型数据一个模块index.js
我们以todolist中增加代办事项这个功能为例:
为了开发规范一点我们要采取reducer的分片写法,即一个类型数据一个模块
不使用react-redux书写规范
生产安装redux
yarn add redux复制代码
在src目录下建立store目录
建立index.js和reducer.js
index.js
import { createStore } from 'redux' import reducer from './reducer' const store = new createStore ( reducer ) export default store复制代码
reducer.js
import { combineReducers } from 'redux' const reducer = combineReducers({ }) export default reducer复制代码
建立todos文件夹,依次建立
state.js
const state = { todos : [ { id : 1, text : '睡觉' }, { id : 2, text : '吃饭' }, { id : 3, text : '打豆豆' } ] } export default state复制代码
type.js
export const ADD_TODOS = 'ADD_TODOS'复制代码
actionCreators.js
import * as type from './type' import store from '../index' const actionCreators = { addTodos( value ){ let action = { type : type.ADD_TODOS, payload : value } store.dispatch( action )//相当于vue里的commit,把action发送给reducer } } export default actionCreators复制代码
reducer.js
import * as type from './type' import state from './state' const reducer = ( previousState = state,action) => {//将state赋值给previousState作为初始值 let newState = {//结构出来给newState,以后对newState进行操作 ...previousState } switch (action.type) { case type.ADD_TODOS: newState.todos.push({ id : newState.todos.length + 1, text : action.payload }) break; default: break; } console.log(newState) return newState } export default reducer复制代码
这些完成后我们需要把todos文件夹下的reducer拿到src下的reducer使用,即src目录下的reducer.js文件改为这样
import { combineReducers } from 'redux' import todos from './todos/reducer' const reducer = combineReducers({ todos }) export default reducer复制代码
这样一个Redux就完成了,接着就是创建组件然后调用store来
src目录下建立pages目录,建立todos目录,下建立todo的组件
在组件中调用store里的方法,两个文件,TodoInput里是增加任务的,所以我们应当在TodoInput里调用activeCreators里的方法来执行任务
TodoInput.js
import React,{ Component,Fragment } from 'react' import actionCreators from '../../store/todos/actionCreators'//引入actionCreators class TodoInput extends Component { addTodos = (e) => { let keyCode = e.keyCode let value = e.target.value if ( keyCode === 13 ){ actionCreators.addTodos(value)//调用actionCreators里的方法 } } render () { return ( <Fragment> <input onKeyUp={ this.addTodos } type="text"></input> </Fragment> ) } } export default TodoInput复制代码
TodoContent.js
TodoContent里是数据的展示,这里有几个关键点,Redux里视图更新需要 store.subscribe 来完成,
知识点:
- 列表渲染的方法
- 怎么让actionCreators里的方法执行后视图更新
import React,{ Component,Fragment } from 'react' import store from '../../store/index' const Item = (props) => { return ( <li>{ props.item.text }</li> ) } class TodoContent extends Component { constructor () { super() this.state={ todos : store.getState().todos.todos//reducer里的名称到todos里的state里的数据名称 } } renderItem = () => {//最好的列表渲染方法 return this.state.todos.map( (item,index)=>{ return <Item item={ item } key={ item.id }></Item> }) } componentDidMount(){//视图更新的方法 store.subscribe(()=>{ this.setState({ todos : store.getState().todos.todos }) }) } render () { return ( <Fragment> <ul> { this.renderItem() } </ul> </Fragment> ) } } export default TodoContent复制代码
index.js
import TodoInput from './TodoInput' import TodoContent from './TodoContent' export { TodoInput,TodoContent }复制代码
使用react-redux规范
使用react-redux涉及到的知识点
核心概念
容器组件(智能组件)、UI组件(木偶组件)
react-redux觉得如果一个组件想要使用到store中的数据或者是actionCreator的方法,我们都应该将其变化为容器组件包裹UI组件的样子
其中,容器组件负责连接store,将状态、方法传递给UI组件,UI组件从属性上取得这些api后进行使用
而且,不需要担心是容器组件可以根据UI组件来生成
核心API
Provider 、 connect(mapStateToProps,mapDistpatchToProps)
Provider负责将store相关的api,传入到内部所有的容器组件中
connect负责根据UI组件来生成容器组件
使用方法和细节
我们根据前面没使用react-redux的案例来改造
生产环境安装react-redux
yarn add react-redux复制代码
需要在组件的最外层套上Provider组件,并为其传入store
再在主入口文件用 Provider 组件包裹App组件 ,注意,Provider组件来自react-redux,还需要引入store赋值给Provider
import store from './store' import { Provider } from 'react-redux' ReactDOM.render( <Provider store = { store }> <App /> </Provider> , document.getElementById('root'));复制代码
利用connect将需要使用store相关api的组件变成容器组件嵌套UI组件的模式
connect方法的返回值是一个函数,这个函数接收到UI组件之后会返回一个容器组件,容器内部已经嵌套了UI组件 Provider组件会利用context上下文将自己属性中store传递给自己的子级组件,而容器组件会取得context上面的store相关的api 我们可以在connect函数中传入mapStateToProps/mapDispatchToProps参数来掌控容器组件给UI组件传递属性的过程 *mapStateToProps的作用*: 将store中的state传递到UI组件的属性上 值为一个函数,接收到的就是store中的state 返回值是什么,UI组件的属性上就有什么 并且,因为容器组件中已经做好了store.subscribe的处理,所以一旦store中的状态变化,容器组件就马上能得知,就会重新给UI组件传入新的数据 *问题*: 坑 ? 我们的store中的数据在更新, 但是里面的容器组件中的 props 不更新 分析: 先从组件上着手,查看我们书写的代码, 发现代码没有问题的, 这个时候我们就要去查看数据来源, 而数据来源来自于 reducer , 然后输出一下数据, 发现数据渲染了三次 , 有两次是一个组件在创建的时候, 数据从无到有, 还有一次是容器组件产生的 , 后面我们发送我们的new_state一直在重复初始化, 解决方案: let newState = {...previousState} mapDispatchToProps的作用: 可以将能使用到dispatch的一些方法传递到UI组件上 值为一个函数,接收到的就是store中的dispatch 返回上面,UI组件的属性上就有什么 这个时候actionCreator就变得很纯粹,只需要创建action,dispatch action的动作可以放到mapDispatchToProps的方法中,也就说,在mapDispatchToProps给UI组件传递的函数中将actionCreator创造好的action给dispatch走 但是这样的写法优点不舒服,因为actionCreator里有一个方法,还需要在mapDispatchToProps里再写一个方法 所以可以利用redux中的bindActionCreators将actionCreator中的方法直接放入到UI组件中并且将其返回的action给直接dispatch走 因为在组件中既要用到store中的状态,也要用到actionCreator的方法,导致这个组件引入了很多东西,其实我们可以将这些逻辑封装取出复制代码
import React,{ Component,Fragment } from 'react' import actionCreators from '../../store/todos/actionCreators' import { connect } from 'react-redux' import { bindActionCreators } from 'redux' const Item = (props) => { return ( <li>{ props.item.text }</li> ) } class TodoContent extends Component { renderItem = () => { return this.props.todos.todos.map( (item,index)=>{ return <Item item={ item } key={ item.id }></Item> }) } addTodos = (e) => { let keyCode = e.keyCode let value = e.target.value if ( keyCode === 13 ){ this.props.addTodos(value) } } render () { console.log('render') return ( <Fragment> <input onKeyUp={ this.addTodos } type="text"></input> <ul> { this.renderItem() } </ul> </Fragment> ) } } // const mapStateToProps = ( state ) => {//第一种connect方法 // // return state.todos // return { // todos : state.todos // } // } // const mapDispatchToProps = ( dispatch ) => { // console.log(dispatch) // return bindActionCreators ( actionCreators,dispatch ) // } // export default connect(mapStateToProps,mapDispatchToProps)(TodoContent) export default connect(//第二种connect方法 state => state, dispatch => bindActionCreators(actionCreators,dispatch) )(TodoContent)复制代码
注意:倘若方法和数据使用在不同的组件里,例如上面案例的输入框和列表展示不在同一个组件,那 么列表展示组件可以只引入
export default connect( state => state )(TodoContent)复制代码
任务输入组件需要都使用
export default connect( state => state, dispatch => bindActionCreators(actionCreators,dispatch) )(TodoInput)复制代码
再修改一下stor下的actionCreators.js的文件
import * as type from './type' const actionCreators = { addTodos( value ){ let action = { type : type.ADD_TODOS, payload : value } return action } } export default actionCreators复制代码
改动的就是由 store.dispatch(action)变成return action,因为我们dispatch功能现在交给组件去做了
react-redux的异步工具redux-thunk
安装redux-thunk
yarn add redux-thunk复制代码
使用详细
场景fetch请求一段数据(数据请求是异步的),将todo数据作为数据,根据上面的react-redux后来继续
redux-thunk一个重要的概念, 中间件(applyMiddleware)
我们主要修改store目录下的index.js
import { createStore,applyMiddleware } from 'redux' import thunk from 'redux-thunk' import reducer from './reducer' const store = new createStore( reducer,applyMiddleware(thunk) ) export default store 复制代码
新的store下的index.js为这样
数据请求放在actionCreators.js里
这里的数据请求中的dispatch( action )的写法相当于return action,同样在使用中是会
import * as type from './type' const actionCreators = { getData(){ return dispatch =>{ fetch('/data.json') .then(res=>res.json()) .then(data=>{ console.log('datad',data) let action = { type : type.GET_DATA, payload : data } dispatch( action ) }) .catch(error=>console.log(error)) } }, addTodos(value){ let action = { type : type.ADD_TODOS, payload : value } return action } } export default actionCreators复制代码
在reducer.js里修改下
import * as type from './type' import state from './state' const reducer = (previousState = state,action)=>{ let newState = { ...previousState } switch(action.type){ case type.GET_DATA: newState.todos=action.payload break; case type.ADD_TODOS: newState.todos.push({ id : newState.todos.length + 1, text : action.payload }) break; default: break; } console.log(newState) return newState } export default reducer复制代码
调用
TodoInput.js
import React,{ Component,Fragment } from 'react' // import { connect } from 'react-redux' // import { bindActionCreators } from 'redux' // import actionCreators from '../../store/todos/actionCreators' import { connect } from 'react-redux' import { bindActionCreators } from 'redux' import actionCreators from '../../store/todos/actionCreators' class TodoInput extends Component { addTodos = (e)=>{ let keyCode = e.keyCode let value = e.target.value if (keyCode === 13){ this.props.addTodos(value) } } getData=()=>{ this.props.getData() } render() { return ( <Fragment> <button onClick={ this.getData }>获取数据</button> <input onKeyUp={ this.addTodos } type="text" placeholder="请输入大粑粑"></input> </Fragment> ) } } export default connect( state => state,//必须添加 dispatch => bindActionCreators( actionCreators,dispatch ) )(TodoInput)复制代码
有个特殊的地方,如果一个组件只需要state,那么可以不要dispatch那一块,如果要dispatch,那么数据一定需要
TodoContent.js
import React,{ Component,Fragment } from 'react' import { connect } from 'react-redux' const Item = (props)=>{ return (<li>{ props.item.text }</li>) } class TodoContent extends Component { renderItem = () => { return this.props.todos.todos.map( (item,index)=>{ return <Item item= { item } key ={ item.id }></Item> }) } render () { return ( <Fragment> <ul> { this.renderItem() } </ul> </Fragment> ) } } // export default TodoContent export default connect( state => state )(TodoContent)复制代码
总结redux-thunk
它的使用方法及其简单:
- 安装redux-thunk
- 在创建store的时候使用中间件 import { createStore, applyMiddleware } from 'redux' import thunk from 'redux-thunk' import reducer from './reducer' const store = createStore(reducer, applyMiddleware(thunk) )
- 这个时候,actionCreator的方法就可以返回一个能接收到dispatch的一个函数,我们可以在这个函数中进行异步操作之后,将actionCreator创建好的action给发送
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 前端状态管理与有限状态机
- 为管理复杂组件状态困扰?试试 vue 简单状态管理 Store 模式
- 基于有限状态机的广告状态管理方案及实现
- 基于有限状态机的广告状态管理方案及实现
- vue状态管理演进
- 浅析前端状态管理
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据结构及应用算法教程
2011-5 / 45.00元
《数据结构及应用算法教程(修订版)》从数据类型的角度,分别讨论了四大类型的数据结构的逻辑特性、存储表示及其应用。此外,还专辟一章,以若干实例阐述以抽象数据类型为中心的程序设计方法。书中每一章后都配有适量的习题,以供读者复习提高之用。第1~9章还专门设有“解题指导与示例”一节内容,不仅给出答案,对大部分题目提供了详尽的解答注释;其中的一些算法题还给出了多种解法。书中主要算法和最后一章的实例中的全部程......一起来看看 《数据结构及应用算法教程》 这本书的介绍吧!