Since I have a component with forms, I need the forms to be connected to the component state. The initial data comes from Redux so try to initialize and update the component by setting the state with the props:
componentWillMount = () => {
this.setState({
language: this.props.language || 'en'
})
}
language
is a connected prop and I checked that it is updated in the store.
const mapStateToProps = state => ({
language: state.language
})
I also tried to use componentWillReceiveProps
and componentWillUpdate
but it doesn't work. I get the initial state, and even though the store and the connected props change, the component's state doesn't update.
{this.props.language} // updates
{this.state.language} // doesn't change
What is the correct way to manage forms from Redux data?
The render
part:
render () {
const {classes, theme, web} = this.props
const language = (
<CardContent>
<Typography type="headline">
Language
</Typography>
<Divider/>
<form className={classes.container} autoComplete="off">
<FormControl fullWidth margin="normal">
<InputLabel htmlFor="language">Select Block</InputLabel>
<Select
value={this.state.language} // <==================== language
onChange={this.handleLanguaheChange}
input={<Input id="language"/>}
>
<MenuItem value={'en'}>English</MenuItem>
<MenuItem value={'he'}>עברית</MenuItem>
</Select>
</FormControl>
</form>
</CardContent>
)
...
return (
<Grid
container
spacing={theme.spacing.unit * 3}
justify={'space-between'}
className={classes.gridWrap}
>
<Grid item xs={6}>
<Card className={classes.card}>
{language}
</Card>
...
First, you are using an arrow function for componentWillMount. Rule of thumb is, do not use arrow functions for life-cycle hooks(componentWillMount, shouldComponentUpdate, ...etc). It's usual to setState in componentWillMount hook. But never set state in componentDidMount. please try to re-write it as,
constructor(props) {
super(props)
this.state = {
language: 'en',
}
}
componentWillMount() {
const { language } = this.props
if (language) this.setState(prevState => ({ language: prevState.language = language }))
}
in some exceptional cases, such as i wrote two classes in a single .js file(like i said, some exceptions) and i couldn't be able to modify it from componentWillMount as expected(later noted, the props are modified by the child class). in such cases, you can override it in render
render() {
const { language } = this.props
if (language) this.setState(prevState => ({ language: prevState.language = language }))
To accomplish this with React Hooks:
useRef()
The posted example didn't really make sense to me so here is the problem I faced:
I have a form with component state that I needed to clear out when the redux state changed.
To accomplish this my component looks like this:
import { useSelector } from 'react-redux';
import React, { useState, useEffect, useRef } from 'react';
const CreateCase = () => {
//redux state
const accounts = useSelector(state => state.accounts);
//component state
const [productId, setProductId] = useState(undefined);
const prevAccountRef = useRef<string>();
useEffect(() => {
//compare current with previous account and clear productId if changed
if (account.id != prevAccountRef.current) {
setProductId(undefined);
}
//set previous account for next render
prevAccountRef.current = account.id;
});
//... render
}
It's very important that you only run setState
inside of useEffect
conditionally.
even though the store and the connected props change, the component's state doesn't update
The way you have it written, the state won't update unless you explicitly update it using setState()
(most likely in the componentWillReceiveProps()
method).
When you use mapStateToProps()
with the Redux connect()
HOC, you are mapping your Redux state to your component through its props, so in your case this.props.language
will update when the Redux stored updates.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With