Reactjs 异步渲染组件
Posted
技术标签:
【中文标题】Reactjs 异步渲染组件【英文标题】:Reactjs async rendering of components 【发布时间】:2015-01-27 08:19:35 【问题描述】:我想在我的 ajax 请求完成后渲染我的组件。
下面你可以看到我的代码
var CategoriesSetup = React.createClass(
render: function()
var rows = [];
$.get('http://foobar.io/api/v1/listings/categories/').done(function (data)
$.each(data, function(index, element)
rows.push(<OptionRow obj=element />);
);
return (<Input type='select'>rows</Input>)
)
);
但我收到以下错误,因为我在我的 ajax 请求的 done 方法中返回渲染。
Uncaught Error: Invariant Violation: CategoriesSetup.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
有没有办法在开始渲染之前等待我的 ajax 请求结束?
【问题讨论】:
另外,一个小小的挑剔但在 render() 例程中进行数据检索并不是一个好主意。保持 render() 进行渲染并抽象出其余部分。此外,您可能只想获取该数据一次,而不是每次渲染组件时。 【参考方案1】:异步状态管理 (Playground)
以下解决方案允许异步状态管理,如果实施正确,可用于 HTTP 相关要求。
要求
仅重新渲染消耗 observable 的元素。 自动订阅和取消订阅 observable。 支持多个和联合 observables。 提供加载状态 简单易行预期行为
return (
<Async select=[names$]>
result => <div>result</div>
</Async>
);
上面提供的示例将订阅可观察的names$
。 Async
组件的内容/子组件将在可观察对象上触发 next 时重新渲染,不会导致当前组件重新渲染。
异步组件
export type AsyncProps<T extends any[]> = select: [K in keyof T]: Observable<T[K]> , children: (result?: any[]) => JSX.Element ;
export type AsyncState = result?: any[] ;
export default class Async<T extends any[]> extends Component<AsyncProps<T>, AsyncState>
private subscription!: Subscription;
constructor(props: AsyncProps<T>)
super(props);
this.state = ;
componentDidMount()
this.subscription = combineLatest(this.props.select)
.subscribe(result => this.setState( result: result as T ))
componentWillUnmount()
this.subscription.unsubscribe();
render()
return (
<Fragment>
this.props.children(this.state.result)
</Fragment>
);
【讨论】:
【参考方案2】:组件异步渲染的基本示例如下:
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
export default class YourComponent extends React.PureComponent
constructor(props)
super(props);
this.state =
data: null
componentDidMount()
const data =
optPost: 'userToStat01',
message: 'We make a research of fetch'
;
const endpoint = 'http://example.com/api/phpGetPost.php';
const setState = this.setState.bind(this);
fetch(endpoint,
method: 'POST',
body: JSON.stringify(data)
)
.then((resp) => resp.json())
.then(function(response)
setState(data: response.message);
);
render()
return (<div>
this.state.data === null ?
<div>Loading</div>
:
<div>this.state.data</div>
</div>);
【讨论】:
【参考方案3】:有两种方法可以处理这个问题,你选择哪种取决于哪个组件应该拥有数据和加载状态。
将Ajax请求移入父级并有条件地渲染组件:
var Parent = React.createClass(
getInitialState: function()
return data: null ;
,
componentDidMount: function()
$.get('http://foobar.io/api/v1/listings/categories/').done(function(data)
this.setState(data: data);
.bind(this));
,
render: function()
if (this.state.data)
return <CategoriesSetup data=this.state.data />;
return <div>Loading...</div>;
);
将 Ajax 请求保留在组件中,并在加载时有条件地呈现其他内容:
var CategoriesSetup = React.createClass(
getInitialState: function()
return data: null ;
,
componentDidMount: function()
$.get('http://foobar.io/api/v1/listings/categories/').done(function(data)
this.setState(data: data);
.bind(this));
,
render: function()
if (this.state.data)
return <Input type="select">this.state.data.map(this.renderRow)</Input>;
return <div>Loading...</div>;
,
renderRow: function(row)
return <OptionRow obj=row />;
);
【讨论】:
我在 2017 年偶然发现了这个答案,这两个最好的解决方案仍然是最好用的吗? @Dan React 基于 props 和 state 渲染 UI,因此核心概念将保持不变——执行 Ajax 请求,设置一些状态,然后重新渲染一些东西。然而,像高阶组件这样的模式变得越来越流行,展示了如何抽象出复杂性。if (this.state.data)
应该是if (this.state && this.state.data)
,因为有时状态可能为空。
@Timo Hm,在什么情况下this.state
会是null
?
@Timo 在构造函数中初始化状态以上是关于Reactjs 异步渲染组件的主要内容,如果未能解决你的问题,请参考以下文章