【问题标题】:Deal with randomly delayed promises in React在 React 中处理随机延迟的 promise
【发布时间】:2019-01-16 03:54:27
【问题描述】:

有时,在评估 React 项目时,我会遇到这样的情况:

export default () => new Promise((resolve, reject) => {
  setTimeout(() => (Math.round(Math.random()) === 0 ? resolve(countries) : reject()), 100);
});

模拟可能有也可能没有延迟的 API。

我的问题是,当我想在 React 组件中获取这个承诺时,特别是在 ComponentDidMount() 中,我需要做什么来确保 render() 将等待这个承诺来呈现我需要的一切?围绕它的最佳做法是什么?

谢谢!

【问题讨论】:

  • 我不确定你在问什么——render 会在调用后立即呈现。组件需要能够在其数据可用之前进行渲染,即使它只是一个空渲染。或者你可以await/etc,但这会阻止一切,这通常是不受欢迎的。
  • 另外:To simulate an API that might or might not have a delay. 这不是模拟的。正在模拟的是一个固定的延迟,之后承诺可能会或可能不会遇到错误。大概是为了检查你的捕获错误。
  • 你不需要做任何特别的事情。一个承诺是总是异步的(延迟的),所以你只需用then()setState()正常处理它。

标签: javascript reactjs promise


【解决方案1】:

这并不特定于使用随机延迟或完全使用承诺的承诺。零延迟setTimeout 或立即解决的承诺会产生相同的结果,尽管几乎看不到。 render的执行不能延期。

初始渲染将以任何方式执行。如果组件状态异步更改,render 应该正确处理初始状态:

state = { data: null };

componentDidMount() {
  Promise.resolve('foo').then(data => this.setState({ data }));
}

render() {
  return this.state.data ? (
    <div>{this.state.data}</div>
  ) : (
    'No data'
  );
}

【讨论】:

    【解决方案2】:

    您不需要做任何事情。该组件应该仍然能够在等待时呈现,例如由模拟 API 调用的结果填充的某些状态。当 promise 解决时,如果它在组件上设置了一些状态,那么组件将使用新数据重新渲染。

    【讨论】:

      【解决方案3】:

      你可以在你的组件中拥有一个状态 isLoading,当 Promise 解决时你设置为 false,然后使用它来渲染 null 直到那时。

      示例

      const countries = ["gb", "se"];
      const getCountries = () =>
        new Promise((resolve, reject) => {
          setTimeout(
            () => (Math.round(Math.random()) === 0 ? resolve(countries) : reject()),
            2000
          );
        });
      
      class App extends React.Component {
        state = { isLoading: true, error: "", countries: [] };
      
        componentDidMount() {
          getCountries()
            .then(countries => {
              this.setState({ isLoading: false, countries });
            })
            .catch(() => {
              this.setState({ isLoading: false, error: "Fetching countries failed" });
            });
        }
      
        render() {
          const { isLoading, error, countries } = this.state;
      
          if (isLoading) {
            return null;
          }
          if (error) {
            return <div>{error}</div>;
          }
      
          return (
            <div>
              {countries.map(country => (
                <div key={country}>{country}</div>
              ))}
            </div>
          );
        }
      }
      
      ReactDOM.render(<App />, document.getElementById("root"));
      <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
      <div id="root"></div>

      【讨论】:

        【解决方案4】:

        你应该在你的状态中存储一个变量来表明你的承诺是否完成。为此,您可以await 您的承诺并设置您的状态,或者使用.then 并在函数的回调中设置您的状态。

        一个最小的代码如下所示:

        class MyComponent extends React.Component {
            constructor(props) {
                super(props)
        
                this.state = {
                    show: false
                }
            }
        
            componentDidMount = async () => {
                try {
                    await new Promise((resolve, reject) => {
                        setTimeout(() => (Math.round(Math.random()) === 0 ? resolve(countries) : reject()), 100);
                    });
                    this.setState({ show: true })
                } catch(err){
        
                }
            }
        
            render = () => this.state.show ? <div>My content</div> : <div/>
        }
        

        您显然可以用您导出的变量替换创建的 Promise,并将渲染的组件更改为您想要的任何内容。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-26
          • 1970-01-01
          • 2020-10-03
          • 1970-01-01
          • 1970-01-01
          • 2011-03-17
          相关资源
          最近更新 更多