05- redux的理解

例子来源于网上的视频教程,总结一下。

redux原理图

05- redux的理解_第1张图片

action

  1. 动作的对象
  2. 包含2个属性
    type:标识属性,值为字符串,唯一,必要属性
  3. 例子:{type: ‘ADD_STUDENT’,data:{ name:‘tom’ , age:18 }}

reducer

  1. 用于初始化状态,加工状态
  2. 加工时,根据旧的state和action,产生新的state的纯函数

store

  1. 将state、action、reducer联系在一起
  2. 如何得到此对象?
    (1)import {createStore} from ‘redux’
    (2)import reducer from ‘./reducers’
    (3)const store = createStore(reducer)
  3. 此对象的功能
    (1)getState():得到state
    (2)dispatch():分发action,触发reducer调用,产生新的state
    (3)subscribe():注册监听,当产生了新的state时,自动调用

精简版redux

下载redux npm i redux

  1. 创建action 通过redux里面的一个方法 createStore 把reducers传入
import {
     createStore} from 'redux';
import {
     countReducers} from './countReducers'
export default createStore(countReducers);
  1. 创建reducers 因为是一个计算的例子 所以起名为countReducers
export const countReducers = (preState=0,action) =>{
     
  switch(action.type){
     
    case 'add' :
      return preState + action.data*1;
    case 'sub' :
      return preState - action.data*1;
    default :
      return preState
  }
}
  1. 在App.js里面写入例子的相关代码
import React, {
      Component } from 'react';
import store from './redux/store';
export default class App extends Component {
     
  state={
     
    selectValue : 1
  }
  //加
  add = () =>{
     
    const {
     selectValue} = this.state;
    store.dispatch({
     type:'add',data:selectValue});
  }
  //减
  sub = () =>{
     
    const {
     selectValue} = this.state;
    store.dispatch({
     type:'sub',data:selectValue});
  }
  //异步加
  asyncAdd = () =>{
     
    const {
     selectValue} = this.state;
    setTimeout(() => {
     
      store.dispatch({
     type:'add',data:selectValue});
    }, 1000);
  }
  //奇数加
  oddAdd = () =>{
     
    const {
     selectValue} = this.state;
    const count = store.getState();
    if(count%2===1){
     
      store.dispatch({
     type:'add',data:selectValue});
    }
  }
  render() {
     
    
    return (
      <div>
        <h1>count:{
     store.getState()}</h1>
        <select onChange={
     (e)=>this.setState({
     selectValue:e.target.value})}>
          <option value='1'>1</option>
          <option value='2'>2</option>
          <option value='3'>3</option>
        </select>
        <button onClick={
     this.add}>+</button>
        <button onClick={
     this.sub}>-</button>
        <button onClick={
     this.asyncAdd}>异步加</button>
        <button onClick={
     this.oddAdd}>奇数加</button>
      </div>
    );
  }
}
  1. 因为redux是一个第三方库 它只能帮我们管理状态 但是不能像react里面的状态一样一旦改变就自动render 所以我们要用store.subscribe()来进行监听redux里面的状态,一旦改变进行实时的更新
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'));
})

精简版结束,里面没有涉及到actions因为action仅仅只是一个obj的对象。我们可以直接写一个对象替代,在后面的例子中我们会加入actions文件

redux完整版

和上一版的区别是增加了actions.js为我们生成action方法,在app.js发布方法不需要写对象了。直接调用actions.js里面的方法即可,为了防止因为马虎写错单词,我们可以新建一个constant.js文件来声明常量

  1. 创建constant.js存储常量
export const ADD = 'add'
export const SUB = 'sub'
  1. 创建actions.js用来创建action
import {
      ADD,SUB } from './constant';
export const add = (data) =>({
     type: ADD,data});
export const sub = (data) =>({
     type:SUB,data})
  1. 把字符串用声明好的常量代替
import {
      ADD,SUB } from './constant';
export const countReducers = (preState=0,action) =>{
     
  switch(action.type){
     
    case ADD :
      return preState + action.data*1;
    case SUB :
      return preState - action.data*1;
    default :
      return preState
  }
}
  1. 事件触发时dispatch acions.js中的函数即可
import {
      add,sub } from './redux/countActions';
  //加
  add = () =>{
     
    const {
     selectValue} = this.state;
    store.dispatch(add(selectValue));
  }
  //减
  sub = () =>{
     
    const {
     selectValue} = this.state;
    store.dispatch(sub(selectValue));
  }
  //异步加
  asyncAdd = () =>{
     
    const {
     selectValue} = this.state;
    setTimeout(() => {
     
      store.dispatch(add(selectValue));
    }, 1000);
  }
  //奇数加
  oddAdd = () =>{
     
    const {
     selectValue} = this.state;
    const count = store.getState();
    if(count%2===1){
     
      store.dispatch(add(selectValue));
    }
  }

异步action

上面的例子有一个异步加的方法,他其实就是一个异步方法。异步action不是必须要使用的,可以把异步方法写到组件内。这样就不需要使用异步action了。就向上面的例子一样。

这个例子与异步action的区别就好比去饭店买了一份蛋炒饭,你可以等待5分钟再通知服务员点餐。这可以告诉服务员一份蛋炒饭5分钟之后上菜。这两种方法都可以实现5分钟之后来一份蛋炒饭这个目的,只是实现的方式不同,所以异步的action不是必须使用的。

同步action返回的是一个对象,异步action返回的是一个函数。

怎么使用异步action呢

redux不支持异步action,因此我们需要下载一个插件redux-thunk。可以用它通知store当接收到一个异步action返回的函数时,执行一下这个函数。

不引入这个插件会报错
05- redux的理解_第2张图片

  1. 引入插件,在store.js中
import {
     createStore,applyMiddleware} from 'redux';
import {
     countReducers} from './countReducers'
import thunk from 'redux-thunk';
export default createStore(countReducers,applyMiddleware(thunk));
  1. 写一个异步的action,异步action通常都要分发一个同步的action。返回的函数自带一个dispatch方法不需要特意的去引用store
import {
      ADD,SUB } from './constant';
export const add = (data) =>({
     type: ADD,data});
export const sub = (data) =>({
     type:SUB,data});
export const asyncAdd = (data) =>{
     
  return (dispatch) =>{
     
    setTimeout(() => {
     
      dispatch(add(data)) //store.dispathch(add(data))
    }, 1000);
  }
}
  1. 把之前的异步加改写
  //异步加
  asyncAdd = () =>{
     
    const {
     selectValue} = this.state;
      store.dispatch(asyncAdd(selectValue));
  }

异步action完成

react-redux的基本使用

  1. 所有的UI组件都应该包裹一个容器组件, 他们是父子关系
  2. 容器组件是真正和redux打交道的,里面可以随意的使用redux的api
  3. UI组件中不能使用任何redux的api
  4. 容器组件会传给UI组件:(1).redux中保存的状态。(2)用于操作状态的方法
  5. 备注:容器给UI传递:状态、操作状态的方法,均通过props传递。
    05- redux的理解_第3张图片
  6. 在react-redux中引入store
import React, {
      Component } from 'react';
import Count from  './Container/Count'
import store from './redux/store'
export default class App extends Component {
     
  
  render() {
     
    
    return (
      <div>
        <Count store={
     store}></Count>
      </div>
    );
  }
}
  1. 创建ui组件 CountUI
import React, {
      Component } from 'react';
class CountUI extends Component {
     
  state={
     
    selectValue : 1
  }
  //加
  add = () =>{
     
    const {
     selectValue} = this.state;
    this.props.add(selectValue)
  }
  //减
  sub = () =>{
     
    const {
     selectValue} = this.state;
    this.props.sub(selectValue)
  }
  //异步加
  asyncAdd = () =>{
     
    const {
     selectValue} = this.state;
    this.props.asyncAdd(selectValue)
  }
  //奇数加
  oddAdd = () =>{
     
    const {
     selectValue} = this.state;
    if(this.props.count % 2 ===1){
     
      this.props.add(selectValue)
    }
    
  }
  render() {
     
    
    return (
      <div>
        <h1>count:{
     this.props.count}</h1>
        <select onChange={
     (e)=>this.setState({
     selectValue:e.target.value})}>
          <option value='1'>1</option>
          <option value='2'>2</option>
          <option value='3'>3</option>
        </select>
        <button onClick={
     this.add}>+</button>
        <button onClick={
     this.sub}>-</button>
        <button onClick={
     this.asyncAdd}>异步加</button>
        <button onClick={
     this.oddAdd}>奇数加</button>
      </div>
    );
  }
}
 
export default CountUI;
  1. 创建容器组件 Count.jsx 通过connect和store交换数据,然后通过props的方式传给子组件CountUI
import {
      connect } from 'react-redux';
import CountUI from '../Components/CountUI'
import {
     add,asyncAdd,sub} from '../redux/countActions'
const mapStateToProps = (state) =>{
     
  return{
     
    count: state
  }
}
const mapDispatchToProps = (dispatch) =>{
     
  return {
     
    add : (data)=>dispatch(add(data)),
    asyncAdd : (data)=>dispatch(asyncAdd(data)),
    sub : (data)=>dispatch(sub(data)),
  }
}
export default connect(mapStateToProps,mapDispatchToProps)(CountUI)

优化react-redux

  1. connect优化 当你的mapDispatchToPros传入的是一个对象时。react-redux会帮你自动dispatch
import {
      connect } from 'react-redux';
import CountUI from '../Components/CountUI'
import {
     add,asyncAdd,sub} from '../redux/countActions'
// const mapStateToProps = (state) =>{
     
//   return{
     
//     count: state
//   }
// }
// const mapDispatchToProps = (dispatch) =>{
     
//   return {
     
//     add : (data)=>dispatch(add(data)),
//     asyncAdd : (data)=>dispatch(asyncAdd(data)),
//     sub : (data)=>dispatch(sub(data)),
//   }
// }
export default connect(
  state=>({
     count:state}),
  {
     
    add,
    asyncAdd,
    sub
  }
)(CountUI)
  1. 不需要监听redux的状态改变
import React from 'react';
import ReactDOM from 'react-dom'
import App from "./App";

ReactDOM.render(<App />,document.getElementById('root'));

// store.subscribe(()=>{
     
//   ReactDOM.render(,document.getElementById('root'));
// })


  1. 可以试用 来进行store的引入,而不需要一个个的传入store

app.js

import React, {
      Component } from 'react';
import Count from  './Container/Count'
import store from './redux/store'
export default class App extends Component {
     
  
  render() {
     
    
    return (
      <div>
        <Countx></Count>
        //
        //
        //
        //
      </div>
    );
  }
}

修改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 store={
     store}>
    <App />
  </Provider>
,document.getElementById('root'));

  1. 合并UI组件和容器组件,删除components。把countUI复制到容器组件count.jsx中。这样两个文件就合并成了一个文件
import {
      connect } from 'react-redux';
import React, {
      Component } from 'react';
import {
     add,asyncAdd,sub} from '../redux/countActions'
class CountUI extends Component {
     
  state={
     
    selectValue : 1
  }
  //加
  add = () =>{
     
    const {
     selectValue} = this.state;
    this.props.add(selectValue)
  }
  //减
  sub = () =>{
     
    const {
     selectValue} = this.state;
    this.props.sub(selectValue)
  }
  //异步加
  asyncAdd = () =>{
     
    const {
     selectValue} = this.state;
    this.props.asyncAdd(selectValue)
  }
  //奇数加
  oddAdd = () =>{
     
    const {
     selectValue} = this.state;
    if(this.props.count % 2 ===1){
     
      this.props.add(selectValue)
    }
    
  }
  render() {
     
    
    return (
      <div>
        <h1>count:{
     this.props.count}</h1>
        <select onChange={
     (e)=>this.setState({
     selectValue:e.target.value})}>
          <option value='1'>1</option>
          <option value='2'>2</option>
          <option value='3'>3</option>
        </select>
        <button onClick={
     this.add}>+</button>
        <button onClick={
     this.sub}>-</button>
        <button onClick={
     this.asyncAdd}>异步加</button>
        <button onClick={
     this.oddAdd}>奇数加</button>
      </div>
    );
  }
}
export default connect(
  state=>({
     count:state}),
  {
     
    add,
    asyncAdd,
    sub
  }
)(CountUI)

react-redux最终版

新增一个组件person 和 count 共享状态
修改目录结构
redux文件夹下新建actions文件夹和reducers文件夹,把所有的action和reducer全部放入对应的文件夹中
05- redux的理解_第4张图片
person的action为

import {
      ADD_PERSON } from "../constant";
export const addPerson = (obj) => ({
     type: ADD_PERSON, data:obj})

person的reducer为


import {
     
  ADD_PERSON
} from "../constant";

const initPerson = [{
     
  name: '张三',
  id: 1,
  hobby: '篮球'
}]
export const person = (preState = initPerson, action) => {
     
  const {
     
    type,
    data
  } = action;
  switch (type) {
     
    case ADD_PERSON:
      return [...preState, data]
    default:
      return preState
  }
}

因为现在有person和count两个reducer所以给store就不能只是count的reducer了。这时候就要用combineReducers来把reducer联合一起
修改store.js

import {
     createStore,applyMiddleware,combineReducers} from 'redux';
import {
     count} from './reducers/count'
import {
      person } from './reducers/person';

import thunk from 'redux-thunk';

export default createStore(combineReducers({
     count,person}),applyMiddleware(thunk));

因为修改combineReducers就相当于修改了redux里面存储的结构。只有一个count组件时,redux里面仅仅是一个0。现在redux存储的是一个对象,{count:0,person:{…person内容}}
所以count.jsx的connect也应该修改

export default connect(
  state=>({
     count:state.count,person: state.person}),
  {
     
    add,
    asyncAdd,
    sub
  }
)(CountUI)

person.jsx组件内容

import React, {
      Component } from 'react';
import {
      connect } from 'react-redux';
import {
      addPerson } from '../redux/actions/person';
class Person extends Component {
     
  state = {
     }
  add = () =>{
     
   this.props.addPerson({
     name:this.name.value,hobby:this.hobby.value,id:this.name.value})
  }
  render() {
     
    return (
      <div>
        <input ref={
     (name)=> this.name = name} type="text" />
        <input ref={
     (hobby)=> this.hobby = hobby} type="text" />
        <button onClick={
     this.add}>添加</button>
        <h1>和为:{
     this.props.count}</h1>
        <ul>
          {
     
            this.props.person.map((p)=>{
     
              return <li key={
     p.id}>{
     p.name}-----{
     p.hobby}</li>
            })
          }
        </ul>
      </div>
    );
  }
}
export default connect(
  state => ({
      count: state.count, person: state.person }),
  {
     
    addPerson
  })(Person);

你可能感兴趣的:(react,js,react)