酶:使用浅的redux存储更新不会触发componentDidUpdate

时间:2018-11-13 15:05:41

标签: reactjs redux react-redux enzyme

我无法测试我的React组件的一个非常特定的用例。在这种情况下,我有一个组件,该组件在安装时分派一个动作,然后在第一次分派的结果进入后分派另一个动作。

我认为问题出在酶的shallow方法中而不在组件中调用componentDidUpdate。我用最简单的代码重现了该问题,并确认如果我使用mount而不是shallow,该问题就消失了。但是,enzyme's documentation说,从版本3开始,shallow确实调用了React的生命周期方法,例如componentDidUpdate。当然,我不能在测试中使用mount,因为我不想挂载整个树(对我而言,这意味着要装载整个应用程序)。

因此,我想知道:这是否是酶的错误,还是我在使用该库时缺少某些东西?

这是我的代码示例:

import * as React from 'react';
import { connect } from 'react-redux';
import { createStore } from 'redux';

import { shallow } from 'enzyme';
import sinon from 'sinon';


const actions = {
    // This would fetch a resource on the network.
    getList: () => {},

    receiveList: list => {
        return {
            type: 'RECEIVE_LIST',
            list,
        };
    },

    // This would fetch a list of resources on the network.
    getObjects: () => {},
};


const reducer = (state = { list: [] }, action) => {
    switch (action.type) {
        case 'RECEIVE_LIST':
            return { ...state, list: action.list };
        default:
            return state;
    }
};


class MyAppBase extends React.Component {
    componentDidMount() {
        this.props.dispatch(actions.getList());
    }

    componentDidUpdate(nextProps) {
        if (nextProps.list !== this.props.list) {
            this.props.dispatch(actions.getObjects(nextProps.list));
        }
    }

    render() {
        return null;
    }
}


const MyApp = connect(state => { return { list: state.list }; })(MyAppBase);



describe('<MyApp>', () => {
    it('fetches objects once list is received', () => {
        // Mock actions that call the network.
        sinon.stub(actions, 'getList');
        actions.getList.returns({type: 'whatever'});
        sinon.stub(actions, 'getObjects');
        actions.getObjects.returns({type: 'whatever'});

        // Create a redux store.
        const store = createStore(reducer);

        // Create the component.
        const wrapper = shallow(<MyApp store={store} />);

        // Verify that `componentDidMount` was called but not `componentDidUpdate`.
        expect(actions.getList.callCount).toEqual(1);
        expect(actions.getObjects.callCount).toEqual(0);

        // Dispatch an action that will change the redux store.
        store.dispatch(actions.receiveList([ 'aa', 'bb' ]));

        // Expect the `componentDidUpdate` method to be called.
        expect(actions.getObjects.callCount).toEqual(1);

        // This doesn't work, for some reason `componentDidUpdate` is never called.
    });
});

我为此使用的软件包版本:

"react": "16.6.0",
"react-dom": "16.6.0",
"react-redux": "5.1.0",
"redux": "4.0.1",
"enzyme": "3.7.0",
"enzyme-adapter-react-16": "1.6.0",
"sinon": "7.1.0"

谢谢!

1 个答案:

答案 0 :(得分:1)

酶的“浅”方法似乎不完全支持“ componentDidUpdate”方法。

安装了<form th:object="${myobject}"> <select class="selectpicker" id="tech" th:field="*{technology}"> <option th:each="technology:${technology}" th:value="${technology}" th:text="${technology}"> </option></select> <form>的组件似乎仅在调用shallow之后才调用componentDidUpdate。商店以新状态更新也没关系,包装器也没有更新。

可以通过更改测试以执行以下操作来确认:

wrapper.setProps()

一种解决方法是在// Dispatch an action that will change the redux store. store.dispatch(actions.receiveList([ 'aa', 'bb' ])); // Will print '[]' console.log(wrapper.instance().props.list); // Create a new wrapper with the current store: const wrapper2 = shallow(<MyApp store={store} />); // Will print '['aa', 'bb']' console.log(wrapper2.instance().props.list) 之后调用setProps(如果可行,最好使用store.dispatch代替mount):

shallow

此外,// Dispatch an action that will change the redux store. store.dispatch(actions.receiveList([ 'aa', 'bb' ])); // Manually cause componentDidUpdate to trigger wrapper.setProps({ list: ['aa', 'bb'] }); 可以通过componentDidUpdate方法来触发,以单击或更改按钮或输入。