react中redux的使用

以一个counter计数器组件为例,实现加减和异步加法

3123123123123

实现效果图如下12343:

image

111231234123444123321232133211231231fchangxujkadfjkfdsakljsdf
jkjasdfljasdfsdafjklsajdf

index.jsx -- 入口


import React from 'react';
import {createStore,combineReducers,applyMiddleware} from 'redux';
import { Provider } from 'react-redux'
import thunkMiddleware from 'redux-thunk'

import * as reducers from './reducer/reducer.jsx';
import Counter from './components/Counter.jsx';
import LoginForm from './components/Login.jsx';

/**
* 创建store
* reducers是什么?你可以查看下面reducer.jsx代码内容
* combineReducers(reducers):是将多个reducer合并一起创建进store
* applyMiddleware(thunkMiddleware):注入一个可以实现异步dispatch的插件,
*/
let store = createStore(combineReducers(reducers),applyMiddleware(thunkMiddleware));

// :将store透传进所有子组件内,所有子组件都可以通过 react-dedux的connect获取store
export default () => {
  return (
    
        
    
  );
};

Counter.jsx -- 计数器组件代码

import React from 'react';
import { connect } from 'react-redux'
import {AddDelay,Add,Dec} from '../reducer/action.jsx';


class Counter extends React.Component{
  constructor(props){
    super(props);
  }

  render(){
    const {reCounter,dispatch}=this.props;
    return (
      

当前计数器:{reCounter.value}

{/* 点击后计数器+1 */} {/* 点击后计数器会在2秒后 +2 用来模拟接口调用 */}
); } } /** * mapStateToProps的作用是将store传递进来的state,进行筛选后暴露给组件 * 这里仅仅把store里面reCounter这个对象暴露给Countre组件 * 所以Counter内可以通过 this.props.reCounter 获取到这个对象 * state:store传递进来的所有reducer * return {} 你可以把你需要暴露给组件的对象筛选return,当然也可以直接将整个state return */ function mapStateToProps(state) { return {reCounter:state.reCounter}; } /** * connect作用是将store和当前组件进行捆绑 * mapStateToProps 函数作用是处理store传入的state对象然后选择需要暴露给组件用的state对象 */ export default connect(mapStateToProps)(Counter)

redcuer.jsx -- 存放所有redcuer


/**
 * 处理加减法
 */
export function reCounter(state = {value:0,loading:false}, action) {
  let value = typeof action.value === 'undefined' ? 1 : action.value;
  switch (action.type) {
    case 'COUNTER_LOADING': return {...state, loading:action.value };
    case 'COUNTER_ADD':     return {...state, value:state.value + value };
    case 'COUNTER_DEC':     return {...state, value:state.value - value };
    default: return state;
  }
}

action.jsx -- 存放所有被组件直接使用的action,为什么需要action这一层,我这里做了个演示,一来是为了避免使用 dispatch({type:"消息名称",value:""}) 这种难看的写法

二来是为了能统一处理一条消息的封装和发送


/**
 * value:增加的值
 * time:延迟多少ms触发
 */
export function AddDelay(value,time) {
  return (dispatch, getState) => {
    return new Promise(reslove => {
      dispatch({type:'COUNTER_LOADING',value:true});
      setTimeout(() => {
        dispatch({ type: 'COUNTER_ADD', value: value });
        dispatch({type:'COUNTER_LOADING',value:false});
        reslove();
      }, time);
    })
  }
}

/**
 * value:增加的值
 */
export function Add(value) {
  return (dispatch, getState) => {
    return new Promise(reslove => {
      dispatch({ type: 'COUNTER_ADD', value: value });
      reslove();
    })
  }
}
/**
 * value:减少的值
 */
export function Dec(value) {
  return (dispatch, getState) => {
    return new Promise(reslove => {
      dispatch({ type: 'COUNTER_DEC', value: value });
      reslove();
    })
  }
}

常见问题

dispatch后值的更新时机

// 方式一
const onClick=(e)=>{
    console.log(reCounter.value);//当前值为1
    dispatch({ type: 'COUNTER_ADD', value: 1 });
    console.log(reCounter.value);//结果还是1
}
//方式二
const onClick=async (e)=>{
    await new Promise(resolve=>setTimeout(resolve,1));
    console.log(reCounter.value);//当前值为1
    dispatch({ type: 'COUNTER_ADD', value: 1 });
    console.log(reCounter.value);//结果变为了2
}

阻塞式dispatch更新值方法

假设我们reducer管理一个叫user的对象{name:"姓名",detail:"我是姓名"}
在组件内有一个方法用来监听name是否发生改变,一旦发生改变就重新设置detail的值
当用户输入name发生变化时需要将detail设置为 我是${name}

一开始你可能想这样处理:

const User=(props)=>{
  const onNameChange= async (e)=>{
    //更新user下name属性
    await dispatch({...props.user,name:e.target.value});
   // 此处的监听可能存在于子组件中,这里为了方便展示所以直接下载了dispatch后
    await listener_nameChange(e.target.value);
    console.log(props.user);
  }

  //监听到name发生变更后,立刻更新了detail的值
 const listener_nameChange = async (newValue)=>{
    await dispatch({...props.user,detail:`i am ${newValue}`})
 }

  return (
    
) }

这里的log打印结果显然最终是detail发生了变更而name没有

解决方法

const User=(props)=>{
  onNameChange(e){
    //更新user下name属性
    dispatch({...props.user,name:e.target.value});
  }
   
  listener_nameChange(newValue){
    dispatch({...props.user,detail:`i am ${newValue}`})
  }
   // ✅ 正确方式应该在props值发生变更时监听,并且处理
  useEffect(()=>{
    listener_nameChange(props.user.name)
  },[props.user.name)
  

  return (
    
) }

你可能感兴趣的:(react中redux的使用)