在获取所有信息之前,如何阻止要呈现的 React 组件?

IT技术 javascript reactjs
2021-03-24 12:04:13

我需要在渲染我的组件之前获取一些信息。该信息将由 API 提供并通过 ajax 调用获取。

我只是想在渲染我的组件之前等待 10 秒钟,但它说:

Uncaught Invariant Violation: Login.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.

我可以在兑现Promise后呈现我的组件吗?

/** Page Login */
class Login extends React.Component {

  /**
   * @constructor
   * @param {object} props La fonction super() appelle le parent pour y transmettre ses propriétés
   */
  constructor(props) {
    super(props);

    this.handleFormSubmit = this.handleFormSubmit.bind(this);
  }

  /**
   * Reçoit les valeurs des formulaires
   */
  handleFormSubmit(data) {
    const { dispatch } = this.props;

    dispatch(fetchLoginAuth(data));
  }

  normalRender() {
    return (
      <div id="login-page">
        <div className="container-fluid">
          <div className="row">
            <div className="col-md-2">
              <Link to="/" className="home-link"><img src={BASE_URL + '/assets/img/logo.svg'} alt="Logo" /></Link>
            </div>
          </div>
          <div className="row">
            <div className="col-lg-4 col-lg-offset-4">
              <h1><FormattedMessage {...messages.loginPageTitle} /></h1>
            </div>
          </div>
          {React.cloneElement(this.props.children || <div />, { onSubmit: this.handleFormSubmit, login: this.props.login })}
        </div>
      </div>
    );
  }

  /**
   * Render le component - ReactTransitionGroup
   * @return {JSX} Rend la page Registration
   */
  render() {
    setTimeout(this.normalRender, 10000);
  }
}

我将 ES6 与 JSX、redux、带有 react-router 的通用路由器一起使用。

非常感谢您的帮助!

6个回答

这是我通常做的事情:

class Login extends React.Component {
    constructor(props) {
        //IMPLEMENT OTHER JUNK HERE
        this.state = {
            data: null //This is what our data will eventually be loaded into
        };
    }
    componentDidMount() {
        this.loadData();
    }
    loadData() {
        /*LOAD DATA, INSERT BELOW LINE IN CALLBACK FUNCTION
            this.setState({
                data: //LOADED DATA
            });
        */
    }
    render() {
        if (!this.state.data) {
            return <div />
        }

        //WE HAVE DATA, DO A NORMAL RENDER
        return (
            <div id="login-page">
                <div className="container-fluid">
                    <div className="row">
                        <div className="col-md-2">
                            <Link to="/" className="home-link"><img src={BASE_URL + '/assets/img/logo.svg'} alt="Logo" /></Link>
                        </div>
                    </div>
                    <div className="row">
                        <div className="col-lg-4 col-lg-offset-4">
                            <h1><FormattedMessage {...messages.loginPageTitle} /></h1>
                        </div>
                    </div>
                    {React.cloneElement(this.props.children || <div />, { onSubmit: this.handleFormSubmit, login: this.props.login })}
                </div>
            </div>
        );
    }
}

这是将要发生的事情的细分......

  1. 组件将要加载
  2. componentDidMount() 触发,运行 loadData()
  3. loadData() 启动ajax请求,在ajax请求返回数据之前返回,因为我们喜欢异步数据加载
  4. 渲染()运行。由于this.state.datais null,我们已进入 if 块,并<div />返回。
  5. Ajax 数据加载完成,并进行this.setState()调用,这会强制重新渲染。
  6. render() 再次运行。由于this.state.data现在包含一个值,我们跳过 if 块并渲染我们的正常内容。

编辑(2019 年 10 月 11 日):将 componentWillMount()迁移到 componentDidMount()

对我来说,这仅在我将 .length 属性添加到检查中时才有效,即使状态设置为空数组也是如此。如果您先将 state 设置为 null,则它会按规定工作。但我猜一个空数组由于某种原因在反应中评估为真。
2021-05-28 12:04:13

总是让 React 渲染。

当你在做一些异步的事情时,展示一个加载微调器或其他东西。

render() {
  <div>
    { this.state.isLoading &&
    <div>Loading.. please wait!</div>
    }
    { !this.state.isLoading &&
    <div>My data has arrived!</div>
    }
  </div>
}
我不喜欢加载微调器,我想要一些材料设计加载栏在顶部或像 youtube。谢谢您的回答!这是一个好方法
2021-05-22 12:04:13
如果已经有一个 DOM 渲染的服务器端,我该怎么办?我不想用装载机代替它。我想保留它。但是当页面加载客户端时,它会杀死我的服务器端呈现的内容:(
2021-06-02 12:04:13

使用构造函数接受答案的另一种方法。我个人觉得这更清洁。

class Menu extends Component {

state = {}

constructor(props) {
    super(props)
    loadData().then(data =>
        this.setState({data: data})
    )
}

async loadData() {
  //get your data
}

render() {
    if (isEmpty(this.state)) {
        return <div>Loading</div>
    }
    return (
        <div id="site">
            {data}
        </div>
    )
 }

你可以尝试类似的东西

/** Page Login */
class Login extends React.Component {
    constructor(props) {
    ...
      this.state = {
        ready: false
      };
    }
    componentWillMount() {
       setTimeout(this.handleLoading, 10000);
    }
    handleLoading() {
      this.setState({ ready: true });
    }
    render() {
       if(!this.state.ready)
         return null;
       return normalRender();
    }
}
这是错误的:在这里检查:您还可以返回 null 或 false 以指示您不希望呈现任何内容。在幕后,React 渲染了一个 <noscript> 标签以使用我们当前的差异算法。当返回 null 或 false 时,ReactDOM.findDOMNode(this) 将返回 null。
2021-06-02 12:04:13
@molson504x 空 div 的问题在于,您无法知道 div 是否具有某些默认情况下在屏幕上显示某些内容的样式,使用 <noscript> 您可以确定不会显示任何内容。
2021-06-04 12:04:13
永远不要阻止渲染。返回 null 可能会引发错误。渲染一个空的 div 总是更好。
2021-06-14 12:04:13
Franco Risso:有道理。根据我的阅读,你最好返回一个空的 div,但我忘记了背后的逻辑是什么。
2021-06-19 12:04:13

暂停渲染似乎很麻烦......

为什么不使用一些占位符子组件渲染组件的一部分……然后,当 ajax 调用完成时,触发一个操作来更改状态并渲染原始组件。

在用户体验和优雅方面都会更好。

我希望尽可能少地进行 ui 转换。我不喜欢这个 -> imgur.com/p2ZcsbF
2021-06-17 12:04:13