[英]setState from inside of a callback to render related content in a React component
I'm stuck with conditional content rendering, depending on a value presence. 我坚持使用条件内容渲染,具体取决于值的存在。 In the component, if API key is not given, I want to show an input with a button.
在组件中,如果未提供API密钥,我想显示带有按钮的输入。 When the API key is stored using
electron-json-storage
and as a state, the component renders another html. 当使用
electron-json-storage
并以状态electron-json-storage
API密钥时,该组件将呈现另一个html。
My problem is I cannot assign the state during component's construction. 我的问题是在构造组件期间无法分配状态。
// @flow
import React, { Component } from 'react';
import storage from 'electron-json-storage';
import {
Button,
Popover,
PopoverInteractionKind,
Position
} from '@blueprintjs/core';
export default class UserButton extends Component {
constructor() {
super();
// -----------------------------------------------------------
// HERE - I'm trying to assign keys from storage via callback
// Unfortunately it doesn't work
// It throws Cannot read property 'is_loggedin' of null
// when renders content={loginContent[this.state.is_loggedin]}
// -----------------------------------------------------------
storage.get('auth', (error, data) => {
if (error) throw error;
this.state = {
api_key: data.user.api_key,
is_loggedin: data.user.is_loggedin
};
});
this.handleTextChange = this.handleTextChange.bind(this);
this.handleSaveClick = this.handleSaveClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
}
handleTextChange(e) {
this.setState({ api_key: e.target.value });
}
handleSaveClick() {
this.setState({ is_loggedin: 1 });
storage.set('auth', { user: this.state }, function (error) {
if (error) throw error;
});
this.forceUpdate();
}
handleLogoutClick() {
this.setState({ is_loggedin: 0 });
storage.remove('auth', function (error) {
if (error) throw error;
});
this.forceUpdate();
}
render() {
const loginContent = ([
// Not logged in
<div>
<label className="pt-label .modifier">
<input
onChange={this.handleTextChange}
autoFocus={true}
className="pt-input modifier"
type="text"
placeholder="Your API key"
/>
</label>
<Button
className="pt-intent-primary pt-fill"
onClick={this.handleSaveClick}
>
Save
</Button>
</div>,
// Logged in
<div>
<Button
className="pt-intent-primary pt-fill"
onClick={this.handleLogoutClick}
>
Change API key
</Button>
</div>
]);
return (
<Popover
content={loginContent[this.state.is_loggedin]}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_RIGHT}
popoverClassName="pt-popover-content-sizing"
>
<Button className="pt-button pt-minimal pt-icon-user" />
</Popover>
);
}
}
How this could be done? 如何做到这一点?
You are probably rendering the component before the callback is called, and so state
is still empty. 您可能在调用回调之前渲染了组件,因此
state
仍然为空。 What you could do is add a temporary, is_loading
state in the constructor that renders a loading message/spinner in the page until the callback is called. 您可以做的是在构造函数中添加一个临时的
is_loading
状态,该状态会在页面中呈现加载消息/微调is_loading
,直到调用回调。
constructor() {
super();
this.state = { is_loading: true };
storage.get('auth', (error, data) => {
if (error) throw error;
this.setState({
is_loading: false,
api_key: data.user.api_key,
is_loggedin: data.user.is_loggedin
});
});
this.handleTextChange = this.handleTextChange.bind(this);
this.handleSaveClick = this.handleSaveClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
}
// ...
render() {
// ...
return (
<Popover
content={this.state.is_loading? "<div>Loading...</div>": loginContent[this.state.is_loggedin]}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_RIGHT}
popoverClassName="pt-popover-content-sizing"
>
<Button className="pt-button pt-minimal pt-icon-user" />
</Popover>
);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.