簡體   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