class Select extends React.PureComponent {
constructor(props) {
super(props)
this.state = { value: this.props.defaultValue }
this.handleChange = this.handleChange.bind(this)
}
handleChange(e) {
e.persist()
if (typeof this.props.onDataChange !== 'undefined') {
this.setState({ value: e.target.value }, () => this.props.onDataChange(e))
} else {
this.setState({ value: e.target.value })
}
}
render() {
const { options } = this.props
return (
<div>
<select
value={this.state.value}
onChange={this.handleChange}
>
{options.map((option, i) => {
const value = option.value || option.path || null
const label = option.label || option.name || option
return (
<option key={`option-${i}`} value={value}>
{label}
</option>
)
})}
</select>
</div>
)
}
}
class Display extends React.PureComponent {
constructor(props) {
super(props)
}
async getSomeValues() {
try {
this.setState({ isReady: false })
await Axios.get(`some-values`)
.then(async (result) => {
this.setState({
values: result.data.values,
default: result.data.default
})
})
} catch (error) {
console.log(error)
} finally {
this.setState({ isReady: true })
}
}
componentDidMount() {
this.getSomeValues()
}
render() {
return (
<Select
options={this.state.values}
defaultValue = {this.state.defaultValue}
/>
)
}
}
I'm trying to solve what i believe to be a pretty simple problem. I have a parent component that houses a child component which is rending a select dropdown.
My parent makes a call to an API service and pulls back a list of items that are to be displayed in the select dropdown. My API returns the set of options to be displayed and an initial value to be selected on load.
The initial render takes the defaultValue property and sets the state to be displayed in the initial instance in the select component constructor, the problem i have with this, is that the api call is done after the initial render so the default value always comes out being null.
I need a mechanism to set the value of the select dropdown to an initial value on load but it has to be done as a result of the api call that happens once the component has loaded?
What is the cleanest way to set the state value to whatever is returned from the API on initial load?
I'm sure this must be an easy problem to solve but i keep getting stuck between what i want to do and the load / render patterns in react.
Any help would be appreciated.
I see two options:
Option 1
You can prevent the rendering of your Select
component until the request is finished. This will mean your constructor will fire after you have the data and will be initialized correctly.
render() {
if (this.state.defaultValue) {
return (
<Select
options={this.state.values}
defaultValue={this.state.defaultValue}
/>
)
} else {
return null; // or loading graphic
}
}
Option 2
In your Select
component, use a lifecycle method like componentDidUpdate
to check if the defaultValue
prop has changed from the last render. If so, set the default value in state. This will make it so that defaultValue
only gets set once.
componentDidUpdate(prevProps) {
if (this.props.defaultValue !== prevProps.defaultValue) {
this.setState({ defaultValue: this.props.defaultValue });
}
}