【问题标题】:Why setState interrupt componentDidUpdate?为什么setState中断componentDidUpdate?
【发布时间】:2018-03-01 17:56:35
【问题描述】:

我有这个组件(简化版):

export default class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isLoading: false,
            data: {}
        };
    }

    componentDidUpdate(prevProps, prevState) {
        if(this.props.time && this.props.time !== prevProps.time){
           this.setState({
             isLoading: true
           })
           fetch(...).then(data => {
             this.setState({
               data: data
               isLoading:false
             }
        }
    }
    render(){
      {isLoading, data} = this.state;
      return (isLoading ? /*show spinner*/ : /* show data*/);
    }

}

这个组件工作:它在获取数据时显示一个微调器,然后显示数据。

我正在尝试使用玩笑和酶来测试它:

test('Mounted correctly', async() => {
   let myComponent = mount(<MyComponent time='01-01-18'/>);
   myComponent.setProps({time: '02-01-18'}); //necessary to call componentDidUpdate
   expect(myComponent.state()).toMatchSnapshot();
}

据我所知,要拨打componentDidUpdate您必须拨打setPros (link)。但是,在调试器之后,点击时调用结束:

       this.setState({
         isLoading: true
       })

这有点出乎意料,问题是快照是:

Object {
  "isLoading": true
  "data": {}
}

这当然是我不想要的。我该如何解决这个问题?

更新:我找到了一个(n 丑陋的)解决方案!

问题是我们要测试的是这个setState完成了:

         this.setState({
           data: data
           isLoading:false
         }

现在,即使设置 await myComponent.setProps({time: '02-01-18'});(如其中一个答案中所建议的那样)也不会发生这种情况,因为它不会等待上述 setState 创建的新异步调用。

我找到的唯一解决方案是将回调函数传递给props,并在setState 完成后调用它。回调函数包含我们想要的expect

所以这是最终的结果:

test('Mounted correctly', async() => {
   let myComponent = mount(<MyComponent time='01-01-18'/>);
   const callBackAfterLastSetStateIsCompleted = () => {
      expect(topAsins.state()).toMatchSnapshot();
   }
   myComponent.setProps({time: '02-01-18', testCallBack: callBackAfterLastSetStateIsCompleted}); //necessary to call componentDidUpdate
   expect(myComponent.state()).toMatchSnapshot();
}

并将组件代码修改为:

         this.setState({
           data: data
           isLoading:false
         },this.props.testCallBack);

但是,如您所见,我正在修改生产中的组件仅用于测试目的,这非常丑陋。

现在,我的问题是:我该如何解决这个问题?

【问题讨论】:

  • 您必须等待fetch 真正完成。请注意,fetch 是异步的。见facebook.github.io/jest/docs/en/asynchronous.html
  • 这可能是因为当您执行setState() 时,组件重新渲染并且fetch 在组件再次安装之前运行,在此期间您再次执行setState(),这可能导致这个问题。设置初始状态 isLoading: true 可以解决您的问题,因为您不必在获取之前setState()
  • 顺便说一句,您可能想在componentWillReceiveProps中这样做
  • @Hamms 你的意思是旋转加载器还是什么?你能告诉我更多吗?
  • 请看更新后的问题!

标签: reactjs unit-testing enzyme jestjs


【解决方案1】:

你需要做的就是使用async/awaitlike

test('Mounted correctly', async () => {
   let myComponent = mount(<MyComponent time='01-01-18'/>);
   await myComponent.setProps({time: '02-01-18'}); //necessary to call componentDidUpdate, await used to wait for async action in componentDidUpdate
   expect(myComponent.state()).toMatchSnapshot();
}

【讨论】:

  • 好的,现在调试器检查了我的问题的setState,但是当它到达expect时,状态仍然没有更新:(
猜你喜欢
  • 2015-08-12
  • 1970-01-01
  • 2019-10-23
  • 2016-10-22
  • 2020-03-27
  • 2019-04-24
  • 2020-02-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多