如何在redux状态更改时更新组件状态?

时间:2017-12-07 12:47:28

标签: javascript forms reactjs redux react-redux

由于我有一个带有表单的组件,我需要将表单连接到组件状态。初始数据来自Redux,因此尝试通过使用props设置状态来初始化和更新组件:

componentWillMount = () => {
  this.setState({
    language: this.props.language || 'en'
  })
}

language是一个连接的道具,我检查它是否在商店中更新。

const mapStateToProps = state => ({
  language: state.language
})

我还尝试使用componentWillReceivePropscomponentWillUpdate,但它不起作用。我得到了初始状态,即使商店和连接的道具发生变化,组件的状态也不会更新。

{this.props.language} // updates
{this.state.language} // doesn't change

从Redux数据管理表单的正确方法是什么?

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>
...

6 个答案:

答案 0 :(得分:1)

  

即使商店和连接的道具发生变化,组件的状态也不会更新

编写文字的方式,除非您使用setState()(最有可能是componentWillReceiveProps()方法)明确更新状态,否则状态不会更新。

当您使用mapStateToProps()与Redux connect() HOC时,您正在通过道具将Redux状态映射到您的组件,因此在您的情况下this.props.language将在Redux存储更新时更新。

答案 1 :(得分:1)

首先,您正在为componentWillMount使用箭头功能。经验法则是,请勿将箭头函数用于生命周期挂钩(componentWillMount,shouldComponentUpdate等)。通常在componentWillMount挂钩中设置setState。但是永远不要在componentDidMount中设置状态。 请尝试将其重写为

constructor(props) {
 super(props)
 this.state = {
  language: 'en',
 }
}
componentWillMount() {
 const { language } = this.props
 if (language) this.setState(prevState => ({ language: prevState.language = language }))
}

在某些特殊情况下,例如我在单个.js文件中编写了两个类(如我所说,有些例外),而且我无法按预期从componentWillMount对其进行修改(后来指出,道具已被修改由儿童班)。 在这种情况下,您可以在渲染中覆盖它

render() {
 const { language } = this.props
 if (language) this.setState(prevState => ({ language: prevState.language = language }))

答案 2 :(得分:1)

要使用React Hooks完成此操作:

  1. 使用useRef()跟踪先前的值
  2. 与以前的值进行比较,并有条件地更新本地组件状态

发布的示例对我来说真的没有意义,所以这是我面临的问题:

我有一个表单,其组件状态需要在redux状态更改时清除。

enter image description here

要完成此任务,我的组件应如下所示:

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
}

仅在条件setState内仅运行useEffect非常重要。

答案 3 :(得分:0)

只有在重新渲染组件时才会调用

componentWillReceiveProps

最初当组件首次安装时,它不会被触发。

您无法在componentwillupdate内拨打setState

为了从redux store初始化组件的初始状态,您应该使用constructor

    constructor(props) {

    super(props);

    this.state = {
        language: this.props.language || 'en'
     }
   }

答案 4 :(得分:0)

不确定是否适用,但是最近我遇到了类似的问题,我的情况是由于调用this.setState不能保证 instant 的状态更新;它只是说状态更改将最终生效。

从react-component文档中:

  

将setState()视为请求而非直接命令   更新组件。为了获得更好的感知性能,React可能会   延迟它,然后在一次通过中更新几个组件。反应   不保证状态更改会立即应用。

     

setState()并不总是立即更新组件。它可能   批处理或将更新推迟到以后。这使得阅读this.state   在调用setState()之后立即发生潜在的陷阱。相反,使用   componentDidUpdate或setState回调(setState(updater,   回调)),保证在更新后都会触发   已应用。如果您需要根据之前的状态设置状态   状态,请阅读下面的updater参数。

如果您需要对状态或依赖状态的事物进行一些“即时”更改,则setState()上的回调可用于将事物锁定在适当的位置。回调对我有用。

答案 5 :(得分:0)

this.state = { language: props.language || 'en' }

无需在状态变量内使用this。 而且,只有在父组件具有该值的情况下,才能在挂载子组件之前获得实际的道具。 您可以检查父项是否具有值,然后再检查其子级。