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

lstz6jyr  于 2023-03-06  发布在  Java
关注(0)|答案(6)|浏览(133)

我需要在渲染我的组件之前获取一些信息。这些信息将由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.
我可以在履行承诺后交付组件吗?

/** 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路由器。
非常感谢您的帮助!

cyej8jka

cyej8jka1#

我通常是这样做的:

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.组件即将加载

  1. componentDidMount()触发,运行loadData()
  2. loadData()启动 AJAX 请求,在ajax请求返回数据之前返回,因为我们喜欢异步数据加载
    1.由于this.state.datanull,我们已经传入if块,并返回<div />
  3. AJAX 数据加载完成,并执行this.setState()调用,强制重新呈现。
  4. render()再次运行,由于this.state.data现在包含了一个值,我们跳过if块并呈现我们的普通内容。
    编辑(2019年10月11日):已将组件WillMount()迁移到组件DidMount()
cwxwcias

cwxwcias2#

始终让React渲染。
当您执行异步操作时,显示一个加载微调器或其他东西。

render() {
  <div>
    { this.state.isLoading &&
    <div>Loading.. please wait!</div>
    }
    { !this.state.isLoading &&
    <div>My data has arrived!</div>
    }
  </div>
}
lhcgjxsq

lhcgjxsq3#

更新:这个答案现在已经过时了。你最好远离类,使用钩子。

#######################

使用构造函数来代替公认答案的另一种方法。我个人觉得这更简洁一些。

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>
    )
 }
2vuwiymt

2vuwiymt4#

您可以尝试以下操作

/** 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();
    }
}
pokxtpni

pokxtpni5#

暂停渲染似乎有些笨拙...
为什么不使用占位符子组件来呈现组件的一部分......然后,当 AJAX 调用完成时,触发一个操作来更改状态并呈现原始组件。
无论是在用户体验还是优雅度方面,它都会更好。

0ve6wy6x

0ve6wy6x6#

如果您必须在多个地方处理相同情况,或者您不必使用状态,只是因为要跟踪表示组件中的异步函数回调,有一种简单的方法可以解决这些问题,请参考react-promise
react-promise提供了一个名为usePromisesandbox的钩子(您可以随意使用)

import React from "react";
import usePromise from "react-promise";
import "./styles.css";

const prom = new Promise((resolutionFunc, rejectionFunc) => {
  // call your async return values after succesfull response
  setTimeout(function () {
    resolutionFunc(<h1> Hello World </h1>);
  }, 5000);
});
const App = () => {
  const { value, loading } = usePromise(prom);
  if (loading) return <div> loading </div>;
  return <div>{value}</div>;
};
export default App;

您可以在一段延迟后看到Hello world

相关问题