Javascript 在获取所有信息之前,如何阻止要呈现的 React 组件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35022922/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can i block a React component to be rendered until I fetched all informations?
提问by Crak_mboutin
I need to fetch some informations before rendering my component. The information will be provided by an API and fetched with an ajax call.
我需要在渲染我的组件之前获取一些信息。该信息将由 API 提供并通过 ajax 调用获取。
I'm just trying to wait 10 seconds before rendering my component but it says:
我只是想在渲染我的组件之前等待 10 秒钟,但它说:
Uncaught Invariant Violation: Login.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
Uncaught Invariant Violation: Login.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
Can i render my component after the fulfilment of a 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);
}
}
I use ES6 with JSX, redux, an universal router with react-router.
我将 ES6 与 JSX、redux、带有 react-router 的通用路由器一起使用。
Thank you very much for your help!
非常感谢您的帮助!
回答by molson504x
Here's what I do normally:
这是我通常做的事情:
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>
);
}
}
Here's a breakdown of what is going to happen...
这是将要发生的事情的细分......
- Component is going to load
- componentDidMount() fires, runs loadData()
- loadData() starts ajax request, returns before ajax request returns data because we love asynchronous data loads
- render() runs. Since
this.state.data
isnull
, we have pass into the if block, and<div />
is returned. - Ajax data load finishes, and a
this.setState()
call is made, which forces a re-render. - render() runs again. Since
this.state.data
contains a value now, we skip over the if block and render our normal stuff.
- 组件将要加载
- componentDidMount() 触发,运行 loadData()
- loadData() 启动ajax请求,在ajax请求返回数据之前返回,因为我们喜欢异步数据加载
- 渲染()运行。由于
this.state.data
isnull
,我们已进入 if 块,并<div />
返回。 - Ajax 数据加载完成,并进行
this.setState()
调用,这会强制重新渲染。 - render() 再次运行。由于
this.state.data
现在包含一个值,我们跳过 if 块并渲染我们的正常内容。
Edit (11 Oct 2019): Migrated componentWillMount() to componentDidMount()
编辑(2019 年 10 月 11 日):将 componentWillMount()迁移到 componentDidMount()
回答by azium
Always let React render.
总是让 React 渲染。
While you're doing something asynchronous, show a loading spinner or something.
当你在做一些异步的事情时,展示一个加载微调器或其他东西。
render() {
<div>
{ this.state.isLoading &&
<div>Loading.. please wait!</div>
}
{ !this.state.isLoading &&
<div>My data has arrived!</div>
}
</div>
}
回答by Franco Risso
You can try something like
你可以尝试类似的东西
/** 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();
}
}
回答by Louis
I would have just made this a comment on the top answer but I don't have the reputation.
我本来只想对最佳答案发表评论,但我没有声誉。
componentWillMount() is now deprecated. So it is better to move the loadData call to the constructor
componentWillMount() 现在已弃用。所以最好将 loadData 调用移到构造函数中
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>
)
}
回答by DougieHauser
Suspending the render seems hacky...
暂停渲染似乎很麻烦......
Why not render a part of your component with some placeholder-sub-component.. and then, when the ajax call finishes, fire an action to change the state and render your original component.
为什么不使用一些占位符子组件渲染组件的一部分……然后,当 ajax 调用完成时,触发一个操作来更改状态并渲染原始组件。
It'll be better both in terms of UX and elegance.
在用户体验和优雅方面都会更好。