Javascript 如何在 redux 状态更改时更新组件状态?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/47695491/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to update component state on redux state change?
提问by ilyo
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:
由于我有一个带有表单的组件,我需要将表单连接到组件状态。初始数据来自 Redux,因此尝试通过使用 props 设置状态来初始化和更新组件:
componentWillMount = () => {
this.setState({
language: this.props.language || 'en'
})
}
languageis a connected prop and I checked that it is updated in the store.
language是一个连接道具,我检查了它是否在商店中更新。
const mapStateToProps = state => ({
language: state.language
})
I also tried to use componentWillReceivePropsand componentWillUpdatebut 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.
我也尝试使用componentWillReceiveProps,componentWillUpdate但它不起作用。我得到了初始状态,即使商店和连接的道具发生了变化,组件的状态也不会更新。
{this.props.language} // updates
{this.state.language} // doesn't change
What is the correct way to manage forms from Redux data?
从 Redux 数据管理表单的正确方法是什么?
The renderpart:
该render部分:
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>
...
回答by Sarath Antony
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,
首先,您正在为 componentWillMount 使用箭头函数。经验法则是,不要将箭头函数用于生命周期钩子(componentWillMount、shouldComponentUpdate 等)。通常在 componentWillMount 钩子中设置状态。但永远不要在 componentDidMount 中设置状态。请尝试将其重写为,
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
在某些特殊情况下,例如我在一个 .js 文件中编写了两个类(就像我说的,有些例外)并且我无法按预期从 componentWillMount 修改它(后来指出,道具是由孩子修改的班级)。在这种情况下,您可以在渲染中覆盖它
render() {
const { language } = this.props
if (language) this.setState(prevState => ({ language: prevState.language = language }))
回答by T Porter
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).
按照您编写的方式,状态不会更新,除非您使用setState()(最有可能在componentWillReceiveProps()方法中)显式更新它。
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.languagewill update when the Redux stored updates.
当您mapStateToProps()与 Redux connect()HOC一起使用时,您正在通过其props将您的 Redux 状态映射到您的组件,因此在您的情况下,this.props.language将在 Redux 存储更新时更新。
回答by RIYAJ KHAN
componentWillReceivePropswill be called only when your component re-rendered.
componentWillReceiveProps只有在您的组件重新渲染时才会调用。
Initially when component first time mounting, it not going to triggered.
最初当组件第一次安装时,它不会被触发。
You can not call setStateinside componentwillupdate.
你不能setState在里面打电话componentwillupdate。
In order to initialise the initial state of component from redux store,you should use constructor.
为了从 redux store 初始化组件的初始状态,你应该使用constructor.
constructor(props) {
super(props);
this.state = {
language: this.props.language || 'en'
}
}
回答by JESii
Not sure if this applies, but I ran into a similar problem recently and my case was due to the fact that calling this.setState does not guarantee an instantupdate to state; it only says that the state change will be effected eventually.
不确定这是否适用,但我最近遇到了类似的问题,我的情况是由于调用 this.setState 并不能保证立即更新状态;它只是说最终会影响状态更改。
From the react-component documentation:
从反应组件文档:
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.
setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the updater argument below.
将 setState() 视为更新组件的请求而不是立即命令。为了获得更好的感知性能,React 可能会延迟它,然后一次更新多个组件。React 不保证状态更改会立即应用。
setState() 并不总是立即更新组件。它可能会批量更新或推迟更新。这使得在调用 setState() 之后立即读取 this.state 成为一个潜在的陷阱。相反,请使用 componentDidUpdate 或 setState 回调 (setState(updater, callback)),这两者都保证在应用更新后触发。如果您需要根据之前的状态设置状态,请阅读下面的更新程序参数。
If you need to make some "instant" changes to state or things that depend on state, then there's that callback on setState() that you can use to lock things in place. The callback is what worked for me.
如果您需要对状态或依赖状态的事物进行一些“即时”更改,则可以使用 setState() 上的回调将事物锁定到位。回调对我有用。
回答by Arun Kumar
this.state = {
language: props.language || 'en'
}
this.state = {
language: props.language || 'en'
}
no need to use thisinside the state variable.
And also you 'll get the actual props, only when your parent component has that value, before mounting the children.
You can keep a check in the parent, whether it has the value and after that, you have to mount the children.
不需要this在状态变量内部使用。而且,只有在您的父组件具有该值时,在安装子组件之前,您才会获得实际的道具。您可以检查父项,它是否具有值,然后,您必须安装子项。
回答by NSjonas
To accomplish this with React Hooks:
要使用 React Hooks 完成此操作:
- Track previous value with
useRef() - Compare with previous value and conditionallyupdate the local component state
- 跟踪以前的值
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.
我有一个带有组件状态的表单,当 redux 状态改变时我需要清除它。
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 setStateinside of useEffectconditionally.
有条件地只在setState里面运行是非常重要的useEffect。


