Redux
redux理解学习文档英文文档: https://redux.js.org/中文文档: http://www.redux.org.cn/Github: https://github.com/reactjs/reduxredux是什么redux是一个专门用于做状态管理的JS库(不是react插件库)。它可以用在react, angular, vue等项目中, 但基本与react配合使用。作用: 集中
redux理解
学习文档
-
英文文档: https://redux.js.org/
-
中文文档: http://www.redux.org.cn/
-
Github: https://github.com/reactjs/redux
redux是什么
-
redux是一个专门用于做状态管理的JS库(不是react插件库)。
-
它可以用在react, angular, vue等项目中, 但基本与react配合使用。
-
作用: 集中式管理react应用中多个组件共享的状态。
什么情况下需要使用redux
-
某个组件的状态,需要让其他组件可以随时拿到(共享)。
-
一个组件需要改变另一个组件的状态(通信)。
-
总体原则:能不用就不用, 如果不用比较吃力才考虑使用。
redux工作流程
redux的三个核心概念
action
-
动作的对象
-
包含2个属性
- type:标识属性, 值为字符串, 唯一, 必要属性
- data:数据属性, 值类型任意, 可选属性
-
例子:
{ type: 'ADD_STUDENT',data:{name: 'tom',age:18} }
reducer
-
用于初始化状态、加工状态。
-
加工时,根据旧的state和action, 产生新的state的纯函数****。
store
-
将state、action、reducer联系在一起的对象
-
如何得到此对象?
-
import {createStore} from 'redux'
-
import reducer from './reducers'
-
const store = createStore(reducer)
-
-
此对象的功能?
-
getState()
: 得到state -
dispatch(action)
: 分发action, 触发reducer调用, 产生新的state -
subscribe(listener)
: 注册监听, 当产生了新的state时, 自动调用
-
redux的核心API
createstore()
作用:创建包含指定reducer的store对象
store对象
-
作用: redux库最核心的管理对象
-
它内部维护着:
-
state
-
reducer
-
-
核心方法:
-
getState()
-
dispatch(action)
-
subscribe(listener)
-
-
具体编码:
-
store.getState()
-
store.dispatch({type:'INCREMENT', number})
-
store.subscribe(render)
-
applyMiddleware()
作用:应用上基于redux的中间件(插件库)
combineReducers()
作用:合并多个reducer函数
求和案例
React实现求和案例
import React, { Component } from 'react'
export default class Test extends Component {
state={
sum:0,
}
increament = () => {
const {sum} = this.state
const {value} = this.count
this.setState({sum:sum + value*1})
}
decreament = () => {
const {sum} = this.state
const {value} = this.count
this.setState({sum:sum - value*1})
}
increamentOdd = () => {
const {sum} = this.state
const {value} = this.count
if (sum % 2 !== 0) {
this.setState({sum:sum + 1})
}
}
increamentDelay = () => {
const {sum} = this.state
const {value} = this.count
setTimeout(() => {
this.setState({sum:sum + value*1})
}, 2000);
}
render() {
const {sum} = this.state
return (
<div>
<h2>数的合为:{sum}</h2>
<select ref={c => this.count = c} name="" id="">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increament}>+</button>
<button onClick={this.decreament}>-</button>
<button onClick={this.increamentOdd}>奇数加一</button>
<button onClick={this.increamentDelay}>稍后加一</button>
</div>
)
}
}
通过redux实现(不加Actions Creators)的实现方式
-
安装redux:
npm i redux
-
创建redux文件夹,在文件夹下创建
store.js
和为某个组件单独创建一个reducers
文件,在store.js
文件中写入如下代码:/* 该文件专门用于暴露一个store对象,整个应用只有一个store对象 */ //引入createStore,专门用于创建redux中最为核心的store对象 import {createStore} from 'redux' //引入为Count组件服务的reducer import countReducer from './count_reducer' //暴露store export default createStore(countReducer)
-
在为某个单独组件比如
Count
组件创建的reducers文件中写入如下代码/* 1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数 2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action) */ const initState = 0 //初始化状态 export default function countReducer(preState=initState,action){ // console.log(preState); //从action对象中获取:type、data const {type,data} = action //根据type决定如何加工数据 switch (type) { case 'increment': //如果是加 return preState + data case 'decrement': //若果是减 return preState - data default: return preState } }
-
在Count组件中写下如下代码
import React, { Component } from 'react' //引入store,用于获取redux中保存状态 import store from '../../redux/store' export default class Count extends Component { state = {carName:'奔驰c63'} /* 该块代码的作用是让redux中的代码发生改变时页面能够实现即时渲染, 不过该代码是在组件中实现 componentDidMount(){ //检测redux中状态的变化,只要变化,就调用render store.subscribe(()=>{ this.setState({}) }) } */ //加法 increment = ()=>{ const {value} = this.selectNumber store.dispatch({type:'increment',data:value*1}) } //减法 decrement = ()=>{ const {value} = this.selectNumber store.dispatch({type:'decrement',data:value*1}) } //奇数再加 incrementIfOdd = ()=>{ const {value} = this.selectNumber const count = store.getState() if(count % 2 !== 0){ store.dispatch({type:'increment',data:value*1}) } } //异步加 incrementAsync = ()=>{ const {value} = this.selectNumber setTimeout(()=>{ store.dispatch({type:'increment',data:value*1}) },500) } render() { return ( <div> <h1>当前求和为:{store.getState()}</h1> <select ref={c => this.selectNumber = c}> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button> <button onClick={this.incrementAsync}>异步加</button> </div> ) } }
-
在
index.js
入口文件中实现页面中的数据即时渲染import React from 'react' import ReactDOM from 'react-dom' import App from './App' import store from './redux/store' ReactDOM.render(<App/>,document.getElementById('root')) store.subscribe(()=>{ ReactDOM.render(<App/>,document.getElementById('root')) })
知识点整理:
(1).去除Count组件自身的状态
(2).src下建立:
-redux
-store.js
-count_reducer.js
(3).store.js:
1).引入redux中的createStore函数,创建一个store
2).createStore调用时要传入一个为其服务的reducer
3).记得暴露store对象
(4).count_reducer.js:
1).reducer的本质是一个函数,接收:preState,action,返回加工后的状态
2).reducer有两个作用:初始化状态,加工状态
3).reducer被第一次调用时,是store自动触发的,
传递的preState是undefined,
传递的action是:{type:'@@REDUX/INIT_a.2.b.4}
(5).在index.js中监测store中状态的改变,一旦发生改变重新渲染
备注:redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写。
求和案例完整版(加上Actions对象)
-
在redux文件夹下创建一个专门为某一个组件服务的actions文件比如专门为count组件服务的
count_action.js
文件,中写入如下代码/* 该文件专门为Count组件生成action对象 */ import {INCREMENT,DECREMENT} from './constant' /** * 最开始的写法如下: * createIncrementAction (data) { * return {type:INCREMENT,data} * } * @param {*} data * @returns */ export const createIncrementAction = data => ({type:INCREMENT,data}) export const createDecrementAction = data => ({type:DECREMENT,data})
-
对Count组件中的代码进行如下修改
import React, { Component } from 'react' //引入store,用于获取redux中保存状态 import store from '../../redux/store' //引入actionCreator,专门用于创建action对象 import {createIncrementAction,createDecrementAction} from '../../redux/count_action' export default class Count extends Component { state = {carName:'奔驰c63'} /* componentDidMount(){ //检测redux中状态的变化,只要变化,就调用render store.subscribe(()=>{ this.setState({}) }) } */ //加法 increment = ()=>{ const {value} = this.selectNumber store.dispatch(createIncrementAction(value*1)) } //减法 decrement = ()=>{ const {value} = this.selectNumber store.dispatch(createDecrementAction(value*1)) } //奇数再加 incrementIfOdd = ()=>{ const {value} = this.selectNumber const count = store.getState() if(count % 2 !== 0){ store.dispatch(createIncrementAction(value*1)) } } //异步加 incrementAsync = ()=>{ const {value} = this.selectNumber setTimeout(()=>{ store.dispatch(createIncrementAction(value*1)) },500) } render() { return ( <div> <h1>当前求和为:{store.getState()}</h1> <select ref={c => this.selectNumber = c}> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button> <button onClick={this.incrementAsync}>异步加</button> </div> ) } }
-
创建常量模块,防止单词写错
/* 该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错 */ export const INCREMENT = 'increment' export const DECREMENT = 'decrement'
知识点整理:
新增文件:
-
count_action.js 专门用于创建action对象
-
constant.js 放置容易写错的type值
异步Action
(1).明确:延迟的动作不想交给组件自身,想交给action
(2).何时需要异步action:想要对状态进行操作,但是具体的数据靠异步任务返回。
(3).具体编码:
1).npm i redux-thunk
,并配置在store中
2).创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务。
3).异步任务有结果后,分发一个同步的action去真正操作数据。
(4).备注:异步action不是必须要写的,完全可以自己等待异步任务的结果了再去分发同步action。
-
首先是在Count组件中进行如下修改,把异步的任务交给action文件
import React, { Component } from 'react' //引入store,用于获取redux中保存状态 import store from '../../redux/store' //引入actionCreator,专门用于创建action对象 import { createIncrementAction, createDecrementAction, createIncrementAsyncAction } from '../../redux/count_action' export default class Count extends Component { state = {carName:'奔驰c63'} /* componentDidMount(){ //检测redux中状态的变化,只要变化,就调用render store.subscribe(()=>{ this.setState({}) }) } */ //加法 increment = ()=>{ const {value} = this.selectNumber store.dispatch(createIncrementAction(value*1)) } //减法 decrement = ()=>{ const {value} = this.selectNumber store.dispatch(createDecrementAction(value*1)) } //奇数再加 incrementIfOdd = ()=>{ const {value} = this.selectNumber const count = store.getState() if(count % 2 !== 0){ store.dispatch(createIncrementAction(value*1)) } } //异步加 incrementAsync = ()=>{ const {value} = this.selectNumber // setTimeout(()=>{ store.dispatch(createIncrementAsyncAction(value*1,500)) // },500) } render() { return ( <div> <h1>当前求和为:{store.getState()}</h1> <select ref={c => this.selectNumber = c}> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button> <button onClick={this.incrementAsync}>异步加</button> </div> ) } }
-
在count_aciton文件中进行如下修改
/* 该文件专门为Count组件生成action对象 */ import {INCREMENT,DECREMENT} from './constant' //同步action,就是指action的值为Object类型的一般对象 export const createIncrementAction = data => ({type:INCREMENT,data}) export const createDecrementAction = data => ({type:DECREMENT,data}) //异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。 export const createIncrementAsyncAction = (data,time) => { return (dispatch)=>{ setTimeout(()=>{ dispatch(createIncrementAction(data)) },time) } }
-
在Count组件中进行如下修改
import React, { Component } from 'react' //引入store,用于获取redux中保存状态 import store from '../../redux/store' //引入actionCreator,专门用于创建action对象 import { createIncrementAction, createDecrementAction, createIncrementAsyncAction } from '../../redux/count_action' export default class Count extends Component { state = {carName:'奔驰c63'} /* componentDidMount(){ //检测redux中状态的变化,只要变化,就调用render store.subscribe(()=>{ this.setState({}) }) } */ //加法 increment = ()=>{ const {value} = this.selectNumber store.dispatch(createIncrementAction(value*1)) } //减法 decrement = ()=>{ const {value} = this.selectNumber store.dispatch(createDecrementAction(value*1)) } //奇数再加 incrementIfOdd = ()=>{ const {value} = this.selectNumber const count = store.getState() if(count % 2 !== 0){ store.dispatch(createIncrementAction(value*1)) } } //异步加 incrementAsync = ()=>{ const {value} = this.selectNumber // setTimeout(()=>{ store.dispatch(createIncrementAsyncAction(value*1,500)) // },500) } render() { return ( <div> <h1>当前求和为:{store.getState()}</h1> <select ref={c => this.selectNumber = c}> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button> <button onClick={this.incrementAsync}>异步加</button> </div> ) } }
-
在store文件中引入插件
/* 该文件专门用于暴露一个store对象,整个应用只有一个store对象 */ //引入createStore,专门用于创建redux中最为核心的store对象 import {createStore,applyMiddleware} from 'redux' //引入为Count组件服务的reducer import countReducer from './count_reducer' //引入redux-thunk,用于支持异步action import thunk from 'redux-thunk' //暴露store export default createStore(countReducer,applyMiddleware(thunk))
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)