05- redux的理解

5 篇文章 0 订阅

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

redux原理图

在这里插入图片描述

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返回的函数时,执行一下这个函数。

不引入这个插件会报错
在这里插入图片描述

  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传递。
    在这里插入图片描述
  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(<App />,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>
        //<Count1 store={store}></Count1>
        //<Count2 store={store}></Count2>
        //<Count3 store={store}></Count3>
        //<Count4 store={store}></Count4>
      </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全部放入对应的文件夹中
在这里插入图片描述
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);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值