【发布时间】:2020-02-01 05:19:02
【问题描述】:
我有一个MaterialUI dialog,上面有一些文本字段、下拉菜单和其他内容。每次打开或重新打开对话框时,都需要将其中一些元素设置为某个值。在某些条件存在(例如,加载用户数据)之前,无法加载其他元素。
对于“重置”,我使用的是 onEnter 函数。但是 onEnter 函数在进入之前不会运行(呃!)......但是渲染函数本身仍然会运行 - 这意味着仍然会发生任何逻辑或访问 JSX 中的 javascript 变量。这使得“onEnter”函数无法成为我设置和初始化对话框的地方。
我也不能使用构造函数来设置/重置这个初始状态,因为在构造函数加载时(在应用程序启动时)我需要构造状态的数据可能不可用。现在,我可以在我的渲染函数中让 JSX 变得超级复杂,并为每个数据点设置条件......但这对于每次应用程序更改任何内容时都会重新渲染的东西来说是很多开销。 (即使 'open' 参数设置为 false,出现的材质 UI 对话框也会运行整个渲染功能)。
为材质 ui 对话框处理初始化值的最佳方法是什么?
这是一个超级简单的例子(在现实生活中,想象 getInitialState 是一个更复杂、更慢、并且可能是异步/网络的函数)——让我们假设用户对象在应用程序开始时不可用并且是实际上,一些数据在应用程序启动后很长时间才被提取或输入。此代码失败,因为“用户”在第一次渲染时未定义(发生在 onEnter 运行之前)。
constructor(props) {
super(props);
}
getInitialState = () => {
return {
user: {username: "John Doe"}
}
}
onEnter = () => {
this.setState(this.getInitialState())
}
render() {
const { dialogVisibility } = this.props;
return (
<Dialog open={dialogVisibility} onEnter={this.onEnter}>
<DialogTitle>
Hi, {this.state.user.username}
</DialogTitle>
</Dialog> );
}
我的第一个直觉是在状态中放入一个“isInitialized”变量,并且只有在“isInitialized”为真时才让渲染返回对话框,如下所示:
constructor(props) {
super(props);
this.state = {
isInitialized: false
};
}
getInitialState = () => {
return {
user: {username: "John Doe"}
}
}
onEnter = () => {
this.setState(this.getInitialState(),
() => this.setState({isInitialized:true})
);
}
render() {
const { dialogVisibility } = this.props;
if(!this.state.isInitialized) {
return null;
}
return (
<Dialog open={dialogVisibility} onEnter={this.onEnter}>
<DialogTitle>
Hi, {this.state.user.username}
</DialogTitle>
</Dialog> );
}
我相信您知道...这不起作用,因为我们从未返回 Dialog 以触发 onEnter 事件,而该事件又触发 onEnter 函数并实际初始化数据。我尝试将 !this.state.inInitialized 条件更改为:
if(!this.state.isInitialized) {
this.onEnter();
return null;
}
这行得通...但它给了我一个运行时警告:Warning: Cannot update during an existing state transition (such as withinrender). Render methods should be a pure function of props and state.
这让我读了很多书,特别是这个问题:Calling setState in render is not avoidable 这真的让我回家了,我不应该只是忽略这个警告。此外,此方法导致返回 JSX 中包含的所有逻辑仍然发生......即使对话框没有“打开”。添加一堆复杂的对话框会降低性能。
当然有一种“正确”的方法可以做到这一点。帮助?想法?
【问题讨论】:
标签: javascript reactjs material-ui