Javascript 确保加载所有子项时仅显示父项
我是一个新的反应者,我正在努力应对以下问题。我在react中创建了一个表单,该表单包含一个下拉列表。我需要在多个页面中重用该下拉列表,所以我想让它成为一个完全负责获取所有数据的组件 在表单组件中,我获取所有数据,其中一个字段是selectedServerDataId。selectId字段包含需要在下拉列表中选择的值的IDJavascript 确保加载所有子项时仅显示父项,javascript,reactjs,Javascript,Reactjs,我是一个新的反应者,我正在努力应对以下问题。我在react中创建了一个表单,该表单包含一个下拉列表。我需要在多个页面中重用该下拉列表,所以我想让它成为一个完全负责获取所有数据的组件 在表单组件中,我获取所有数据,其中一个字段是selectedServerDataId。selectId字段包含需要在下拉列表中选择的值的ID <snip includes/> class Arrival extends React.PureComponent { constructor(prop
<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;
类到达扩展了React.PureComponent{
建造师(道具){
超级(道具);
此.state={
formData:{}
};
}
异步组件didmount(){
等待获取(URL.addEditUrl)
.then(response=>response.json())
。然后(数据=>{
this.setState({formData:data});
});
}
render(){
const{formData}=this.state;
返回(
);
}
}
导出默认到达;
父组件中的fetch检索编辑表单的数据,包括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 }
类ServerDataSelector扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
选项:[],
};
}
异步组件didmount(){
等待获取(URL.GetServerData)
.then(response=>response.json())
。然后(数据=>{
this.setState({options:data});
});
}
render(){
const{options}=this.state;
返回(
this.props.value}selectedOption={this.props.value}name={this.props.label}>
{options.map(d=>{d.value}}
//TODO添加模型窗口以操作列表。
);
}
}
导出默认服务器数据选择器
ServerDataSelector{Selector}
当前,当页面呈现时,我首先在下拉列表中看到选定值的ID,然后在一瞬间看到实际的选定值标签
是否有办法确保父组件仅在子组件完全加载完成时渲染 这里的主要问题是,有两个组件具有严格的呈现层次关系(父级->子级),但数据获取责任相同 这导致您必须对多个组件之间按特定顺序进行的数据检索做出反应,这是一个非常重要的并发问题。一种解决方案是使用共享状态容器(使用或),并让这两个组件将其结果保存到此共享状态存储桶中,然后每当存储桶包含所有数据时,您都会将其显示出来(在此之前,您可以显示一个微调器) 一个更简单的解决方案是只需将抓取移动到其中一个组件中,完全消除这种分离数据抓取责任,并允许抓取数据的组件也控制渲染 一种方法是获取父级中的所有数据,并使子级仅为接收数据时呈现的纯组件:
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>
);
}
}
您可以选择显示微调器或加载指示器:
...
{
formData && options ? (
<Selector
label="select"
onChange={this.UpdateFormSelectData.bind(this, "selectedServerDataId")}
options={this.state.options}
value={formData.selectedServerDataId}
/>
) : (
<Spinner />
);
}
。。。
{
formData&选项(
) : (
);
}
或者,您可以让子对象获取所有数据,而父对象只呈现子对象
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>
);
}
}
classserverdataselector扩展React.Component{
// ...
异步组件didmount(){
const[formData,options]=wait Promise.all([
fetch(url.addEditUrl).then(response=>response.json()),
获取(url.GetServerData).then(response=>response.json())
]);
这是我的国家({
值:formData.selectedServerDataId,
选择权
});
}
render(){
返回(
this.state.value}{/*使用state*/}中的值
selectedOption={this.state.value}{/*使用状态中的值*/}
name={this.props.label}
>
{this.state.options.map(d=>(
{d.value}
))}
);
}
}
您还可以在子级中添加微调器,以防止页面抖动,并实现更好的用户体验:
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>
);
}
render(){
如果(!this.state.value | |!this.state.options){
返回;
}
返回(
this.state.value}
selectedOption={this.state.value}
name={this.props.label}
>
{this.state.options.map(d=>(
{d.value}
))}
);
}
经过多次尝试和错误后,我找到了一种解决方法
在我的父状态中,我添加了以下对象:
this.state = {
formData: null,
loadedComponents: {
parentComponentIsLoaded: false,
childComponent1IsLoaded: false,
childComponent2IsLoaded: false,
}
};
然后我在我的父对象中添加了以下两种方法
componentLoaded = (field, data) => {
const { loadedComponents } = this.state;
var fieldName = field + "IsLoaded";
this.setState({ loadedComponents: { ...loadedComponents, [fieldName]: true } });
}
allComponentsLoaded() {
const { loadedComponents } = this.state;
console.log(loadedComponents);
for (var o in loadedComponents) {
if (!loadedComponents[o]) return false;
}
return true;
}
将渲染方法更改为:
return (
formData ?
<Form className={this.allComponentsLoaded() ? '' : 'hidden'} >
<ChildComponet1 {someprops} isLoaded={this.componentLoaded}/>
<ChildComponent2 {someprops} isLoaded={this.componentLoaded}/>
<snip />
</Form> : <div />);
也许这是一个非常糟糕的react设计,您应该实际使用MEM035的答案,但它确实有效感谢您提供了广泛的答案。你的回答让我觉得我试着用一种不是反应的方式来做事情。作为一名后端程序员,我总是尝试制作可重用的组件,并承担1项责任。我将查看提供的库,否则我将使用父加载所有路径。虽然我希望我能找到一种方法来处理这个问题,因为这可以在我正在制作的应用程序中为我节省大量前端代码。很高兴能帮助mate。react中的组件应该是可重用的,您的想法是正确的。无论技术部门(后端、前端等)如何,只要有一个职责,这都是一个坚实的软件工程原则。在所有这些问题上,我都非常同意你的看法。方法中唯一的问题是绘制组件边界的位置。我的建议是基于您给出的小代码示例,但我得到的最好建议是采纳您关于可重用性和单一责任的想法,并改变您的c语言
return (
formData ?
<Form className={this.allComponentsLoaded() ? '' : 'hidden'} >
<ChildComponet1 {someprops} isLoaded={this.componentLoaded}/>
<ChildComponent2 {someprops} isLoaded={this.componentLoaded}/>
<snip />
</Form> : <div />);
this.props.isLoaded('childComponet1', true)