redux/react-redux,reducer 中使用 ++state.num 为什么不能使 react 重新渲染?

input调用changeName是好的,可是这个button调用access就有问题了,其实计数器是增加了,但是没有触发render()方法

import React, { Component } from 'react';
import { render } from 'react-dom';
import { createStore, bindActionCreators } from 'redux';
import { Provider, connect } from 'react-redux';

const reducer = (state = {
    name: '',
    num: 0,
}, action) => {
    const { type, payload = {} } = action;
    switch (type) {
        case 'changeName':
            return {
                name: payload.name,
                num: state.num,
            };
        case 'access':
            return {
                name: state.name,
                num: ++state.num,
            };
        default:
            return state;
    }
};
const store = createStore(reducer);
let actions = {
    changeName(name) {
        return {
            type: 'changeName',
            payload: {
                name,
            },
        };
    },
    access() {
        return {
            type: 'access',
        };
    },
};
actions = bindActionCreators(actions, store.dispatch);

// ===================
class UI extends Component {
    render() {
        const { name, num, access, changeName } = this.props;
        return (<div>
            <h1>名字: {name}</h1>
            <h2>计数器: {num}</h2>
            <input type="text"
                   onChange={(eve) => changeName(eve.target.value.trim())}/>
            <button onClick={() => access()}>计数器增加</button>
        </div>);
    }
};
const UI2 = connect(state => state, () => actions)(UI);
render(
    <Provider store={store}>
        <UI2/>
    </Provider>
    ,
    document.getElementById('app'));
阅读 2.1k
1 个回答

state.num + 1 不要 ++state.num

在 Redux 的官方文档中有这么一段话:

It's very important that the reducer stays pure. Things you should never do inside a reducer:

  • Mutate its arguments;
  • Perform side effects like API calls and routing transitions;
  • Call non-pure functions, e.g. Date.now() or Math.random().

We'll explore how to perform side effects in the advanced walkthrough. For now, just remember that the reducer must be pure. Given the same arguments, it should calculate the next state and return it. No surprises. No side effects. No API calls. No mutations. Just a calculation.

意思就是 reducer 必须是一个纯函数,所谓的纯函数,就是:不要在函数内修改参数,不要进行 API 调用,路由切换等有副作用的操作,不要调用非纯函数,只进行计算;纯函数给相同的输入,永远都会有相同的输出。

render 的工作就是计算生成一个新的 state,而不是修改原来的那个 state。

回到你这个问题:

你这里这个 reducer 就不是纯函数,因为 ++state.num 修改了参数 state。

Redux 只有检测到 state 发生变化才会触发订阅的回调函数,也就是说 react-redux 才会重新渲染。

你先把原来的 state.num 加 1,然后返回的新的 state 也是加 1 后的,Redux 将两个 state 进行比对就会发现没有发生任何变化。其实是你成功骗过了 redux。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题