Redux与React-redux

114 阅读5分钟

Redux

认识:redux是一个独立专门用于做状态管理的JS库(不是react插件库)

使用步骤

1.创建reducer

可以使用单独的一个reducer,也可以将多个reducer合并为一个reducer,即:conbineReducers()

action发出命令后将state放入reducer加工函数中,返回新的state,对state进行加工处理

2.创建action

用户是接触不到state的,只能由view触发,所以,这个action可以理解为指令,需要发出多少动作就有多少指令

action是一个对象,必须有一个叫type的参数,定义action类型

异步action需借助第三方库redux-thunk 并结合applyMiddleware使用
import{creareStore,applyMiddleware}from ‘redux’
import thunk from ‘redux-thunk’
const store=createStore(**Reducer,applyMiddleware(thunk))

3.创建store,使用createStore方法

 store可以理解为有多个加工机器的工厂
 
 提供subscribe、dispatch、getState这些方法
 

实践

reducer

/*
1、该文件是用于创建一个Count组件服务的reducer,reducer的本质就是一个函数
2、reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
3、reducer被第一次调用时,是store自动触发的,传递的preState是undefined,传递的action是类似于:{
 type: '@@REDUX/INIT_a.2.b.4'
}
*/
const {INCREMENT, DECREMENT} from './constant'
const initState = 0;//初始化状态,推荐写法
export default function countReducer (preState = initState, action) {
//if(preState === undefined) preState = 0
//从action对象中获取:type、data
 const { type, data} = action
 //根据type决定如何加工数据
 switch (type) {
  case INCREMENT://如果是加
    return preState + data;
   case DECREMENT://如果是减
    return preState - data;
   default: 
    return preState
 }

action

/*
 该文件专门为Count组件生成action对象
*/
function createIncrementAction(data) {
 return {
  type:'increment',
  data
 }
}
function createDecrementAction(data) {
 return {
  type:'decrement',
  data
 }
}
//改造之后
const {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(createDecrementAction(data));
  },time)
 }
}

综合

//引入store,用于获取redux中保存的状态
import store from '../../redux/store'
//引入actionCreator专门用于创建action对象
import {createIncrementAction,createDecrementAction,createIncrementAsyncAction} from '../../redux/count_action'

//componentDidMount() {
 //监测redux中状态的变化,只要变化,就调用render
 //store.subscribe(() => {
   //this.setState({})
 //})
//}

//加法
increment = () => {
 const { value } = this.selectNumber;
 //store.dispatch({type:'increment', date : value * 1});
 store.dispatch(createIncrementAction(value * 1));
}
//减法
decrement = () => {
 const { value } = this.selectNumber;
 //store.dispatch({type:'decrement', date : value * 1});
 store.dispatch(createDecrementAction(value * 1));
}

//奇数再加
incrementIfOdd = () => {
  const { value } = this.selectNumber;
  const count = store.getState();
  if (count % 2 !== 0) {
   //store.dispatch({type:'increment',data : value * 1})
   store.dispatch(createIncrementAction(value * 1));
  }
}
incrementAsync = () => {
 const { value } = this.selectNumber;
 store.dispatch(createIncrementAsyncAction(value * 1 , 500))
}

render() {
 return (
   <div>
     <h1>当前和为: {store.getState()}</h1>
   </div>
  )
}
监测redux中状态的改变,如redux的状态发生了变化,那么重新渲染App组件

import React from "react";
import ReactDOM from "react-dom";
import App from './App';
import store from './store/store';
ReactDOM.render(<App/>,document.getElementById('root'))
// 在这里需要明确的是:redux只是一个状态的管理机制,它不会自动的触发页面的更新,需要我们自己去写
store.subscribe(() => ReactDOM.render(<App/>,document.getElementById('root')))

redux小结

createStore:创建包含指定reducer的store对象

store对象:redux库最核心的管理对象,内部维护着state、reducer

applyMiddleware:应用上基于redux的中间件(redux不支持异步更新,只支持同步数据的修改)

combineReducers:合并多个reducer函数

react-redux

注意事项

1.所有的UI组件都应该包裹一个容器组件,他们是父子关系
2.容器组件是真正和redux打交道的,里面可以随意的使用redux的api
3.UI组件不能使用任何的redux的api
4.容器组件会传给UI组件
   1.redux中保存的状态
   2.用于操作状态的方法
5.容器组件给UI组件的状态方法均通过props传递

两个核心

 Provider
   可参考redux的store.subscribe()方法,,简单来说就是提供一个顶级的组件,将整个应用进行控制。这里的Provider也是类似的功能,并且将整个store作为参数传入了应用
   <Provider store={sotre}>
      <App/>
   </Provider>
   这样所有的组件就能访问redux的数据了
   
   
 connect----连接容器组件与UI组件的桥梁
 语法 connect(需传递的redux状态或者方法)(UI组件)

实践

//引入Count 的ui组件
import CountUI from '../../components/Count'
//引入connect用于连接UI组件与redux
import {connect} from 'react-redux';
import {createIncrementAction} from 'action';
/*
 1、mapStateToProps函数返回的是一个对象;
 2、对象中的key就作为传递给Ui组件props的key,value就作为传递给Ui组件props的value
 3、mapStateToProps用于传递状态
*/
function mapStateToProps(state) {
 return {
 count:state
 }
}
/*
 1、mapDispatchToProps函数返回的是一个对象;
 2、对象中的key就作为传递给Ui组件props的key,value就作为传递给Ui组件props的value
 3、mapDispatchToProps用于传递操作状态的方法
*/
function mapDispatchToProps(dispatch) {
 return {
  jia:(data) => {
   //通知redux执行加法
   dispatch(createIncrementAction(number))
  }
 }
}
//使用connect()()创建并暴露一个Count的容器组件
export default  connect(mapStateToProps, mapDispatchToProps)(CountUI);

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import store from './redux/store';
import { Provider} from 'react-redux';

ReactDOM.render(
//此处需要用Provider包裹App,目的是让App所有的后代容器组件都可以接收到store
 <Provider store = {store}>
  <App />
 </Provider>,
 document.getElementById('root')

优化

1、容器组件和Ui组件整合一个文件;
2、无需自己给容器组件传递store,给<App />包裹一个<Provider store = {store} />即可;
3、使用了react-redux后也不用再给自己检测redux状态的改变了,容器组件可以自动完成这个工作;
4、mapDispatchToProps可以简单的写成一个对象
5、一个组件要和redux打交道,要经过哪几步?
(1)定义好ui组件--不暴露;
(2)引入connect生成一个容器组件,并暴露,写法如下:
connect(
 state=({type:value}),
 {key:xxxAction}
)(UI组件)
(3)在ui组件中通过this.props.xxx读取和操作状态