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. When the API key is stored using electron-json-storage
and as a state, the component renders another 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. 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.
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>
);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.