React - Json 除非我使用 SetTimeout 函数,否则架构表单下拉列表不会初始加载
React - Json Schema Form dropdowns won't load initally unless I use SetTimeout function
这让我和我的团队抓狂。这是相关代码。
在组件的 CDM 中,我们有:
componentDidMount() {
this.getContextID();
this.getConsumerID();
this.getEnvType();
//setTimeout(() => this.setState({ populatedMultiSchema: this.multiSchema }), 200);
//setTimeout(() => this.setState({ populatedMultiUISchema: this.multiUISchema }), 200);
this.setState({ populatedMultiSchema: this.multiSchema });
this.setState({ populatedMultiUISchema: this.multiUISchema });
}
所以列出的 3 种方法中的任何一种都将获取下拉列表的数据。这是一个例子(它们基本上都是一样的)。
getContextID() {
contextIDOptions = [];
console.log("CONVERT_TARGET::", this.props.fetchTarget)
return (
fetch(this.props.fetchTarget + "Configuration/ContextIDs", {
method: 'GET',
//mode: 'cors',
credentials: 'include',
}).then(response => {
if (response.status >= 400) {
this.setState({
value: 'no response - status > 400'
});
throw new Error('no response - throw');
}
return response.json()
}).then(function (json) {
for (var contextID = 0; contextID < json.List.length; contextID++) {
contextIDOptions.push(json.List[contextID]);
}
this.setState({ contextIDArray: contextIDOptions });
console.log("got contextIDs");
}.bind(this)).catch(() => {
this.setState({
value: 'no response - cb catch'
})
})
)
}
所以我们将那里的状态设置为'contextIDArray'。
然后 JSON 模式表单通过它的 multiUISchema 对象引用了这些帮助设置表单值的小部件。
ContextIDWidget = (props) => {
return (
<div>
<input type="text" placeholder="Select one..." className="form-control" list="contextIDSelect" onChange={(event) => props.onChange(event.target.value)} />
<datalist id="contextIDSelect">
{this.state.contextIDArray.map((value, index) => { return <option key={index} value={value}>{value}</option> })}
</datalist>
</div>
)
}
这是 multiUISchema 对象(对本次讨论很重要的部分)
multiUISchema = {
file: {
'ui:widget': this.MultiFileWidget,
classNames: "uiSchema"
},
contextID: {
'ui:widget': this.ContextIDWidget,
classNames: "uiSchema"
},
}
最后在组件的 return 中。
return (
<div className="container" >
<Form
schema={this.state.populatedMultiSchema}
uiSchema={this.state.populatedMultiUISchema}
formData={this.state.formData}
onChange={({ formData }) => { this.setState({ formData }); this.setState({ totalFileSize: this.getMultiFileSize() }); this.checkConversionSupport() }}
onSubmit={this.handleSubmit}
>
长话短说,如果我在表单中使用状态对象,并且我对我使用的对象执行 setState。为什么我第一次加载组件时总是得到一个空白的下拉列表。 DOM(在本例中为下拉列表)是否应该在状态对象更改时使用来自提取的更新数据重新绘制?我的控制台日志在我的检查 window 中显示了获取的数据,因此我知道数据已被获取。这是选项卡组件。如果我离开选项卡或导航到我的 SPA 中的另一个页面,然后返回到该页面,则下拉菜单将全部加载。但是我永远无法让它最初加载,除非我在 CDM 中设置这些超时而不是仅仅设置状态。
setTimeout(() => this.setState({ populatedMultiSchema: this.multiSchema }), 200);
setTimeout(() => this.setState({ populatedMultiUISchema: this.multiUISchema }), 200);
我知道 post 很长,但我觉得我需要包含所有部分才能获得帮助。我可以向您保证,我们已经努力解决这个问题一个多星期了。我们欢迎任何意见。谢谢!
我对你的代码库不是很熟悉。但它看起来像是与异步请求有关的东西。这里:
this.setState({ populatedMultiSchema: this.multiSchema });
this.setState({ populatedMultiUISchema: this.multiUISchema });
这两行将在这些行之前执行:
this.getContextID();
this.getConsumerID();
this.getEnvType();
但您希望它们以相反的顺序执行。不。您的 getContextID
方法向服务器发出请求。 Javascript 是异步的。但是,通过在 asynchronous
函数中使用 await
表达式,您可以暂停执行并等待 Promise
。
所以,只需更新您的 componentDidMount
方法如下:
async componentDidMount() {
await this.getContextID();
await this.getConsumerID();
await this.getEnvType();
this.setState({ populatedMultiSchema: this.multiSchema });
this.setState({ populatedMultiUISchema: this.multiUISchema });
}
Here i created a Codepen 关于 async/await
的用法。评论里有一些细节。想怎么玩就怎么玩。
即使你的问题不是主要由这个引起的,这种方法也更好。您应该使用 async/await or Promise 来处理网络请求。
这让我和我的团队抓狂。这是相关代码。
在组件的 CDM 中,我们有:
componentDidMount() {
this.getContextID();
this.getConsumerID();
this.getEnvType();
//setTimeout(() => this.setState({ populatedMultiSchema: this.multiSchema }), 200);
//setTimeout(() => this.setState({ populatedMultiUISchema: this.multiUISchema }), 200);
this.setState({ populatedMultiSchema: this.multiSchema });
this.setState({ populatedMultiUISchema: this.multiUISchema });
}
所以列出的 3 种方法中的任何一种都将获取下拉列表的数据。这是一个例子(它们基本上都是一样的)。
getContextID() {
contextIDOptions = [];
console.log("CONVERT_TARGET::", this.props.fetchTarget)
return (
fetch(this.props.fetchTarget + "Configuration/ContextIDs", {
method: 'GET',
//mode: 'cors',
credentials: 'include',
}).then(response => {
if (response.status >= 400) {
this.setState({
value: 'no response - status > 400'
});
throw new Error('no response - throw');
}
return response.json()
}).then(function (json) {
for (var contextID = 0; contextID < json.List.length; contextID++) {
contextIDOptions.push(json.List[contextID]);
}
this.setState({ contextIDArray: contextIDOptions });
console.log("got contextIDs");
}.bind(this)).catch(() => {
this.setState({
value: 'no response - cb catch'
})
})
)
}
所以我们将那里的状态设置为'contextIDArray'。
然后 JSON 模式表单通过它的 multiUISchema 对象引用了这些帮助设置表单值的小部件。
ContextIDWidget = (props) => {
return (
<div>
<input type="text" placeholder="Select one..." className="form-control" list="contextIDSelect" onChange={(event) => props.onChange(event.target.value)} />
<datalist id="contextIDSelect">
{this.state.contextIDArray.map((value, index) => { return <option key={index} value={value}>{value}</option> })}
</datalist>
</div>
)
}
这是 multiUISchema 对象(对本次讨论很重要的部分)
multiUISchema = {
file: {
'ui:widget': this.MultiFileWidget,
classNames: "uiSchema"
},
contextID: {
'ui:widget': this.ContextIDWidget,
classNames: "uiSchema"
},
}
最后在组件的 return 中。
return (
<div className="container" >
<Form
schema={this.state.populatedMultiSchema}
uiSchema={this.state.populatedMultiUISchema}
formData={this.state.formData}
onChange={({ formData }) => { this.setState({ formData }); this.setState({ totalFileSize: this.getMultiFileSize() }); this.checkConversionSupport() }}
onSubmit={this.handleSubmit}
>
长话短说,如果我在表单中使用状态对象,并且我对我使用的对象执行 setState。为什么我第一次加载组件时总是得到一个空白的下拉列表。 DOM(在本例中为下拉列表)是否应该在状态对象更改时使用来自提取的更新数据重新绘制?我的控制台日志在我的检查 window 中显示了获取的数据,因此我知道数据已被获取。这是选项卡组件。如果我离开选项卡或导航到我的 SPA 中的另一个页面,然后返回到该页面,则下拉菜单将全部加载。但是我永远无法让它最初加载,除非我在 CDM 中设置这些超时而不是仅仅设置状态。
setTimeout(() => this.setState({ populatedMultiSchema: this.multiSchema }), 200);
setTimeout(() => this.setState({ populatedMultiUISchema: this.multiUISchema }), 200);
我知道 post 很长,但我觉得我需要包含所有部分才能获得帮助。我可以向您保证,我们已经努力解决这个问题一个多星期了。我们欢迎任何意见。谢谢!
我对你的代码库不是很熟悉。但它看起来像是与异步请求有关的东西。这里:
this.setState({ populatedMultiSchema: this.multiSchema });
this.setState({ populatedMultiUISchema: this.multiUISchema });
这两行将在这些行之前执行:
this.getContextID();
this.getConsumerID();
this.getEnvType();
但您希望它们以相反的顺序执行。不。您的 getContextID
方法向服务器发出请求。 Javascript 是异步的。但是,通过在 asynchronous
函数中使用 await
表达式,您可以暂停执行并等待 Promise
。
所以,只需更新您的 componentDidMount
方法如下:
async componentDidMount() {
await this.getContextID();
await this.getConsumerID();
await this.getEnvType();
this.setState({ populatedMultiSchema: this.multiSchema });
this.setState({ populatedMultiUISchema: this.multiUISchema });
}
Here i created a Codepen 关于 async/await
的用法。评论里有一些细节。想怎么玩就怎么玩。
即使你的问题不是主要由这个引起的,这种方法也更好。您应该使用 async/await or Promise 来处理网络请求。