在React中处理随机延迟的承诺

时间:2019-01-15 11:39:07

标签: javascript reactjs promise

有时候,在对React项目进行评估时,我会遇到类似这样的事情:

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

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

我的问题是,当我想在React组件中(特别是在ComponentDidMount()中获取此诺言时,我该怎么做才能确保render()将等待此诺言来呈现所有内容我需要?围绕它的最佳实践是什么?

谢谢!

4 个答案:

答案 0 :(得分:2)

这并不完全适用于使用随机延迟的promise。零延迟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'
  );
}

答案 1 :(得分:1)

您无需执行任何操作。该组件在等待例如由模拟API调用的结果填充的某些状态。当承诺解决时,如果它在组件上设置了某些状态,则将使用新数据重新渲染组件。

答案 2 :(得分:1)

您可以在组件中拥有isLoading状态,当承诺已解决时,您可以将其设置为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>

答案 3 :(得分:1)

您应该在状态中存储一个变量,该变量指示您的诺言是否完成。为此,您可以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,并将呈现的组件更改为所需的任何内容。