Test中的ReactDOM.unmountComponentAtNode()会导致警告

Rob*_*uch 5 reactjs

我构建了我的应用程序wir create-react-app.在最近的版本中,它在Jest中的引导测试设置中添加了一行来卸载组件(请参阅参考资料ReactDOM.unmountComponentAtNode(div)).

import ReactDOM from 'react-dom';
import App from './App';

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div);
  ReactDOM.unmountComponentAtNode(div);
});
Run Code Online (Sandbox Code Playgroud)

当我为我的App组件运行测试时,它会引发警告.

警告:只能更新已安装或安装的组件.这通常意味着您在已卸载的组件上调用了setState,replaceState或forceUpdate.这是一个无操作.

我猜:发生这种情况是因为我有一个异步请求componentDidMount():

fetchFoo(bar) {
  fetch(SOME_URL)
    .then(response => response.json())
    .then(result => this.setState({ result }))
    .catch(error => this.setState({ error }));
}
Run Code Online (Sandbox Code Playgroud)

如果是这种情况,我如何在测试中等待异步请求最终再次卸载组件?我知道我可以在Jest测试中移除一个衬里导致这个,但我想修复它.

wgo*_*l01 9

解决此问题的最简单方法fetch()是在卸载组件时正确取消.在React中使用componentDidMount() 不会取消的异步请求是不好的做法,因为根据网络速度和UI交互,他们可以经常尝试更新未安装组件的状态.要么使用可取消的Promise,要么使用this.shouldCancel实例变量来指示要调用的天气setState(),如下所示:

class LifecycleTest extends React.Component {
  constructor(props){
    super(props)
    this.shouldCancel = false;
    this.state = {
      result:null,
      err:null
    }
  }

  componentDidMount(){
    asyncTask()
      .then(result => !this.shouldCancel ? this.setState({result}) : null)
      .catch(err => !this.shouldCancel ? this.setState({err}) : null);
  }

  componentWillUnmount(){
    this.shouldCancel = true
  }

  render(){
    const {err, result} = this.state
    if(err){
      return <div className="err">{err}</div>
    }else if (result){
      return <div className="result">{result}</div>
    }else{
      return <div className="loading">Loading...</div>
    }        
  }
}
Run Code Online (Sandbox Code Playgroud)

(在webpackbin上查看)

也就是说,如果你真的想在没有改变源的情况下通过这个测试,你可以嘲笑fetch()返回一个Promise永不解决的'dud' .例如,添加它应该可以解决错误:

window.fetch = jest.fn(() => new Promise((accept, reject) => {}))
Run Code Online (Sandbox Code Playgroud)

然而,这是一个可怕的黑客.更好的解决方案是在组件卸载时正确取消网络请求.