关于 React.useEffect() 和 React.useState() 的问题
Posted
技术标签:
【中文标题】关于 React.useEffect() 和 React.useState() 的问题【英文标题】:Question about React.useEffect() and 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>
)
【问题讨论】:
那是因为由于状态值没有变化,所以不会触发使用效果,也不会重新渲染。 完全。我只是不确定为什么在重新选择资产时它不会更新。当资产被多次点击时,您是否能够使用相同的数据或以前的数据更新状态? 【参考方案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>
)
请注意强制重新渲染应该是最后的手段,重新渲染可能是一项相当昂贵的操作,应该小心处理。
【讨论】:
以上是关于关于 React.useEffect() 和 React.useState() 的问题的主要内容,如果未能解决你的问题,请参考以下文章
如果添加了功能依赖关系,则 React useEffect re Renders Infinitely
TypeError: (0 , _react.useEffect) 不是函数
[react] useEffect和useLayoutEffect有什么区别?
React UseEffect 不适用于 firepad 和 firebase