【问题标题】:Question about React.useEffect() and React.useState()关于 React.useEffect() 和 React.useState() 的问题
【发布时间】:2021-01-19 21:46:37
【问题描述】:

我遇到了一个问题,即 useEffect 没有触发基于 useState 更改的重新渲染,或者 useState 没有更改而不会触发 useEffect。一旦我选择了一个应该更新 useState 作为选定组件的资产,然后我选择了另一个它没问题,但是一旦我选择了一个已经被选择的资产,我就注意到了这个问题。没有任何反应?任何建议或任何东西都非常感谢!谢谢!

export default function SingleAsset({svg, name, size = '60', group}) {
  const [assetType, setAssetType] = React.useState(null);
  const [officeType, setOfficeType] = React.useState(null);
  const [industrialType, setIndustrialType] = React.useState(null);
  const [financingType, setFinancingType] = React.useState(null);
  const [investmentType, setInvestmentType] = React.useState(null)
  const acquistionStatus = useSelector(state => state.Acquisition)
  const dispatch = useDispatch()
  const classes = useStyles()

  React.useEffect(() => {
    if(financingType === 'Acquisition') {
      const data = {financingType}
      dispatch(updateFormData(data))
      dispatch(toggleAcquisitionOn())
    }
    if(financingType) {
      if(financingType !== 'Acquisition')  dispatch(toggleAcquisitionOff())
      const data = {financingType}
      dispatch(updateFormData(data))
      
    }
    if(industrialType) {
      const data = {industrialType}
      dispatch(updateFormData(data))
    }
    if(officeType) {
      const data = {officeType}
      dispatch(updateFormData(data))
    }
    if(investmentType) {
      const data = {investmentType}
      dispatch(updateFormData(data))
      console.log(data)
    }
    if(assetType) dispatch(updateAssetData(assetType))
    console.log(financingType)
    console.log(officeType)
    console.log(industrialType)
    console.log(investmentType)
    
  },[investmentType,assetType,officeType,industrialType,financingType])

  const handleSelect = (group, name) => {
    switch(group) {
      case 'main':
        setAssetType(name)
        break
      case 'office': 
        setOfficeType(name)
        break
      case 'industrial':
        setIndustrialType(name)
        break
      case 'financing':
        setFinancingType(name)
        break
      case 'investment':
        setInvestmentType(name)
        break
      default:
        throw new Error('group not found')
    }
  }

  return (
    <Grid
      className={classes.container} 
      item
    >
      <Grid
        container
        direction="column"
        alignItems="center"
      >
        <IconButton onClick={() => handleSelect(group, name)}>
          <img src={svg} color="white" height={size} />
        </IconButton>
        <Typography 
          variant="body1" 
          color="white" 
          align="center"
        >
          {name}
        </Typography>
      </Grid>
    </Grid>         
  )
}

【问题讨论】:

  • 那是因为由于状态值没有变化,所以不会触发使用效果,也不会重新渲染。
  • 完全。我只是不确定为什么在重新选择资产时它不会更新。当资产被多次点击时,您是否能够使用相同的数据或以前的数据更新状态?

标签: javascript reactjs redux


【解决方案1】:

这实际上是一种预期的行为。

React 使用“浅比较”(查看this other great question 了解更多信息),这实质上意味着它将与=== 比较以前的值和新值。这就是不应该改变状态对象的原因。因此,当您的代码尝试将状态更新为它已经拥有的相同值时,它实际上不会这样做......它是相同的,因此不会触发重新渲染。

为了解决这个问题,我们可以强制 React 使用 some clever coding 进行更新,这将使 React 检测到状态变化:

// Setup a new state 
const [, updateState] = useState();
// Create a function that will update state with a new object
// This works because {} === {} is always false, making React trigger a re-render
const forceUpdate = useCallback(() => updateState({}), []);

您的示例代码将是这样的:

export default function SingleAsset({svg, name, size = '60', group}) {
  const [, updateState] = useState();
  const forceUpdate = useCallback(() => updateState({}), []);
  const [assetType, setAssetType] = React.useState(null);
  const [officeType, setOfficeType] = React.useState(null);
  const [industrialType, setIndustrialType] = React.useState(null);
  const [financingType, setFinancingType] = React.useState(null);
  const [investmentType, setInvestmentType] = React.useState(null)
  const acquistionStatus = useSelector(state => state.Acquisition)
  const dispatch = useDispatch()
  const classes = useStyles()

  React.useEffect(() => {
    if(financingType === 'Acquisition') {
      const data = {financingType}
      dispatch(updateFormData(data))
      dispatch(toggleAcquisitionOn())
    }
    if(financingType) {
      if(financingType !== 'Acquisition')  dispatch(toggleAcquisitionOff())
      const data = {financingType}
      dispatch(updateFormData(data))
      
    }
    if(industrialType) {
      const data = {industrialType}
      dispatch(updateFormData(data))
    }
    if(officeType) {
      const data = {officeType}
      dispatch(updateFormData(data))
    }
    if(investmentType) {
      const data = {investmentType}
      dispatch(updateFormData(data))
      console.log(data)
    }
    if(assetType) dispatch(updateAssetData(assetType))
    console.log(financingType)
    console.log(officeType)
    console.log(industrialType)
    console.log(investmentType)
    
  },[investmentType,assetType,officeType,industrialType,financingType])

  const handleSelect = (group, name) => {
    switch(group) {
      case 'main':
        setAssetType(name)
        break
      case 'office': 
        setOfficeType(name)
        break
      case 'industrial':
        setIndustrialType(name)
        break
      case 'financing':
        setFinancingType(name)
        break
      case 'investment':
        setInvestmentType(name)
        break
      default:
        throw new Error('group not found')
    }
  }

  return (
    <Grid
      className={classes.container} 
      item
    >
      <Grid
        container
        direction="column"
        alignItems="center"
      >
        <IconButton onClick={() => {
          handleSelect(group, name);
          forceUpdate(); // <-- this is were the magic happens
        }}>
          <img src={svg} color="white" height={size} />
        </IconButton>
        <Typography 
          variant="body1" 
          color="white" 
          align="center"
        >
          {name}
        </Typography>
      </Grid>
    </Grid>         
  )
}

请注意强制重新渲染应该是最后的手段,重新渲染可能是一项相当昂贵的操作,应该小心处理。

【讨论】:

    猜你喜欢
    • 2020-03-20
    • 1970-01-01
    • 2010-11-26
    • 2012-03-06
    • 2019-04-05
    • 2011-08-09
    • 2010-11-20
    • 1970-01-01
    • 2011-08-09
    相关资源
    最近更新 更多