繁体   English   中英

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

[英]How to update component state on redux state change?

由于我有一个带有表单的组件,我需要将表单连接到组件状态。 初始数据来自 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>
...

首先,您正在为 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 }))
}

在某些特殊情况下,例如我在一个 .js 文件中编写了两个类(就像我说的,有些例外)并且我无法按预期从 componentWillMount 修改它(后来指出,道具是由孩子修改的类)。 在这种情况下,您可以在渲染中覆盖它

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

要使用 React Hooks 完成此操作:

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

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

我有一个带有组件状态的表单,当 redux 状态改变时我需要清除它。

在此处输入图片说明

为了实现这一点,我的组件如下所示:

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
}

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

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

按照您编写的方式,状态不会更新,除非您使用setState() (最有可能在componentWillReceiveProps()方法中)显式更新它。

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

componentWillReceiveProps只会在你的组件重新渲染时被调用。

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

您不能在componentwillupdate内调用setState

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

    constructor(props) {

    super(props);

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

不确定这是否适用,但我最近遇到了类似的问题,我的情况是由于调用 this.setState 并不能保证立即更新状态; 它只是说最终会影响状态更改。

从反应组件文档:

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

setState() 并不总是立即更新组件。 它可能会批量更新或推迟更新。 这使得在调用 setState() 之后立即读取 this.state 成为一个潜在的陷阱。 相反,请使用 componentDidUpdate 或 setState 回调 (setState(updater, callback)),这两者都保证在应用更新后触发。 如果您需要根据之前的状态设置状态,请阅读下面的更新程序参数。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM