我对 react 很陌生,我正在努力解决以下问题。我在 react 中创建了一个表单,该表单包含一个下拉列表。我需要在多个页面中重用该下拉菜单,因此我想将其作为一个组件来完全负责获取所有数据。
在表单组件中,我获取所有数据,其中一个字段是 selectedServerDataId。 selectId 字段包含需要在下拉列表中选择的值的 ID。
<snip includes/>
class Arrival extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
formData: {}
};
}
async componentDidMount() {
await fetch(urls.addEditUrl)
.then(response => response.json())
.then(data => {
this.setState({ formData: data });
});
}
<snip some setstate helpers/>
render() {
const { formData } = this.state;
return (
<Form >
<Selector label="select"
onChange={this.UpdateFormSelectData.bind(this, 'selectedServerDataId')}
value={formData.selectedServerDataId}/>
<DateItem label="date"
allowClear={true}
value={formData.date}
onChange={this.updateFormDateData.bind(this, 'date')}/>
<snip more fields.../>
</Form>);
}
}
export default Arrival;
父组件中的提取检索编辑表单的数据,包括 selectedServerDataId。我的子组件如下所示:
<snip usings />
class ServerDataSelector extends React.Component {
constructor(props) {
super(props);
this.state = {
options: [],
};
}
async componentDidMount() {
await fetch(URLS.GetServerData)
.then(response => response.json())
.then(data => {
this.setState({ options: data });
});
}
render() {
const { options } = this.state;
return (
<FormItem {...formItemLayout} label={t(this.props.label)} >
<Select setValue={this.props.onChange} getValue={() => this.props.value} selectedOption={this.props.value} name={this.props.label}>
{options.map(d => <Option key={d.id} value={d.id}>{d.value}</Option>)}
</Select>
//TODO add model window to manipulate list.
</FormItem>);
}
}
export default ServerDataSelector
ServerDataSelector { Selector }
当前,当页面呈现时,我首先在下拉列表中看到所选值的 ID,然后一瞬间我看到了实际的所选值标签。
有没有办法确保父组件只在子组件完全加载完成时呈现?
最佳答案
您在这里遇到的主要问题是您有两个组件,它们具有严格的呈现层次关系(父 -> 子)但具有同等的数据获取责任。
这导致您必须以特定顺序对多个组件之间的数据检索使用react,这是一个非常重要的并发问题。一种解决方案是使用共享状态容器(使用 Redux 或 Context API )并让两个组件将它们的结果保存到这个共享状态桶中,然后只要桶中有所有数据,你就呈现它(直到那时你例如可以显示微调器)。
一个更简单的解决方案是将获取转移到一个组件中,完全消除这种分离的数据获取责任,并允许获取数据的组件也控制渲染。
一种方法是获取父级中的所有数据,让子级只是一个纯组件,在接收到数据时呈现:
class Arrival extends React.Component {
// ...
async componentDidMount() {
const [formData, options] = await Promise.all([
fetch(urls.addEditUrl).then(response => response.json()),
fetch(URLS.GetServerData).then(response => response.json())
]);
this.setState({ formData, options });
}
render() {
const { formData, options } = this.state;
return (
<Form>
{/* ... */}
{formData &&
options && (
<Selector
label="select"
options={this.state.options} {/* pass the options here */}
onChange={this.UpdateFormSelectData.bind(
this,
"selectedServerDataId"
)}
value={formData.selectedServerDataId}
/>
)}
</Form>
);
}
}
Selector
现在只是一个展示组件,不需要状态:
const ServerDataSelector = props => (
<FormItem {...formItemLayout} label={t(this.props.label)}>
<Select
setValue={this.props.onChange}
getValue={() => this.props.value}
selectedOption={this.props.value}
name={this.props.label}
>
{this.props.options.map(d => ( {/* use props.options */}
<Option key={d.id} value={d.id}>
{d.value}
</Option>
))}
</Select>
</FormItem>
);
您可以选择显示微调器或加载指示器:
...
{
formData && options ? (
<Selector
label="select"
onChange={this.UpdateFormSelectData.bind(this, "selectedServerDataId")}
options={this.state.options}
value={formData.selectedServerDataId}
/>
) : (
<Spinner />
);
}
或者,您可以让子项获取所有数据,而父项只渲染子项。
class ServerDataSelector extends React.Component {
// ...
async componentDidMount() {
const [formData, options] = await Promise.all([
fetch(urls.addEditUrl).then(response => response.json()),
fetch(URLS.GetServerData).then(response => response.json())
]);
this.setState({
value: formData.selectedServerDataId,
options
});
}
render() {
return (
<FormItem {...formItemLayout} label={t(this.props.label)}>
<Select
setValue={this.props.onChange}
getValue={() => this.state.value} {/* use the value from the state */}
selectedOption={this.state.value} {/* use the value from the state */}
name={this.props.label}
>
{this.state.options.map(d => (
<Option key={d.id} value={d.id}>
{d.value}
</Option>
))}
</Select>
</FormItem>
);
}
}
您还可以在 child 中添加一个微调器以防止页面卡顿并允许更好的用户体验:
render() {
if (!this.state.value || !this.state.options) {
return <Spinner />;
}
return (
<FormItem {...formItemLayout} label={t(this.props.label)}>
<Select
setValue={this.props.onChange}
getValue={() => this.state.value}
selectedOption={this.state.value}
name={this.props.label}
>
{this.state.options.map(d => (
<Option key={d.id} value={d.id}>
{d.value}
</Option>
))}
</Select>
</FormItem>
);
}
关于javascript - 确保父项仅在加载所有子项时显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51116620/