数组状态更新后反应不重新渲染
Posted
技术标签:
【中文标题】数组状态更新后反应不重新渲染【英文标题】:React not re-rendering after array state update 【发布时间】:2020-01-13 04:02:08 【问题描述】:我有一个从数组呈现的复选框列表 UI。更新数组后,复选框列表状态不会更新。
我移动了映射列表的代码,但它并没有改变结果。不会发生 DOM 重新渲染,请参见下面的 gif。
我一直在寻找,我发现这个问题已经报告了,但是关于将list.map
代码移出函数的解决方案对我不起作用。
您能建议我一个解决方案吗? 这个问题的根源是什么?
import React, useState from "react"
import
Box,
DropButton,
Grid,
Text,
Calendar,
RangeInput,
CheckBox
from "grommet"
const CalButton = ( label,onSelect ) =>
return (
<DropButton
label= label
dropAlign= top: 'bottom',left: 'left'
margin="small"
dropContent=
<Box pad="medium" background="ligth-3" elevation="small">
<Calendar range size="medium" onSelect= onSelect />
</Box>
/>
)
const RangeButton = ( label,value,onChange,min,max,step,unit,header ) =>
return (
<DropButton
label= value === null ? label : value + ' ' + unit
dropAlign= top: 'bottom',left: 'left'
margin="small"
dropContent=
<Box pad="medium"
background="ligth-3"
elevation="small"
align="center"
>
<Text size="small"> header </Text>
<RangeInput
value= value
min= min max= max
onChange= onChange
step= step
/>
<Text weight="bold"> value </Text>
<Text weight="normal"> unit </Text>
</Box>
/>
)
const FeaturesButton = ( label,features,onChange ) =>
const FeaturesList = ( features,onChange ) => (
<>
features.map( ( item,idx ) => (
<CheckBox
key= item.name
label= item.name
checked= item.checked
onChange= e => onChange( e,idx ) />)
)
</>
)
return (
<DropButton
label= label
dropAlign= top: 'bottom',left: 'left'
margin="small"
dropContent=
<Box pad="medium"
background="ligth-3"
elevation="small"
align="start"
direction="column"
gap="small"
>
<FeaturesList
features=features
onChange=onChange />
</Box>
/>
)
const destApp = () =>
const [ windStrength,setWindStrength ] = useState( null )
const [ windFrequency,setWindFrequency ] = useState( null )
const [ cost,setCost ] = useState( null )
const date = new Date()
const [ month,setMonth ] = useState( date.getMonth() )
const [ listFeatures,setListFeatures ] = useState( [
name: 'Butter flat water',
checked: false,
,
name: 'Moderately flat water',
checked: false,
,
name: '1-2m Waves',
checked: false,
,
name: '2m+ Waves',
checked: false,
,
name: 'Beginer Friendly',
checked: false,
,
name: 'Kite-in-kite-out',
checked: false,
,
name: 'Nightlife',
checked: false,
] )
const months = [ 'January','February','March','April','May','June','July','August','September','October','November','December' ];
const updateFeaturesList = ( e,idx ) =>
listFeatures[ idx ].checked = e.target.checked
const newFeatures = listFeatures
setListFeatures( newFeatures )
console.log( "Updated features list",newFeatures,e.target.checked )
return (
<Grid rows= [ "xsmall","fill" ]
areas= [ [ "filterBar" ],[ "results" ] ]
gap="xxsmall">
<Box gridArea="filterBar"
direction="row-responsive"
gap="xsmall"
pad="xsmall"
justify="center" >
<CalButton label= months[ month ].toLowerCase() onSelect= ( data ) => console.log( data ) />
<RangeButton
label="wind strength"
header="What's your wind preference?"
min="15"
max="45"
unit="kts"
value= windStrength
step= 1
onChange= ( e ) =>
setWindStrength( e.target.value )
console.log( windStrength )
/>
<RangeButton
label="wind frequency"
header="How often does your destination need to be windy?"
min="1"
max="7"
unit="days/week"
value= windFrequency
step= 1
onChange= ( e ) =>
setWindFrequency( e.target.value )
console.log( windFrequency )
/>
<RangeButton
label="cost"
header="Average daily cost: 1 lunch, diner and doubble room at a midrange hotel?"
min="10"
max="400"
unit="€"
value= cost
step= 1
onChange= ( e ) =>
setCost( e.target.value )
console.log( cost )
/>
<FeaturesButton
label="important features "
features= listFeatures
onChange= updateFeaturesList
/>
</Box>
<Box gridArea="results"
margin="">
Results go in here!
</Box>
</Grid>
)
export default destApp
【问题讨论】:
看起来你正在更新listFeatures[ idx ].checked = e.target.checked
此处的变异状态并返回相同的对象,使用传播 (...
) 运算符并设置像 setListFeatures( [...newFeatures] )
这样的状态,这将返回应该触发的新对象重新渲染。
【参考方案1】:
您正在改变 updateFeaturesList
函数中的原始状态。使用setState
的函数形式更新您当前的功能列表:
const updateFeaturesList = (e, idx) =>
const checked = e.target;
setListFeatures(features =>
return features.map((feature, index) =>
if (id === index)
feature = ...feature, checked ;
return feature;
);
);
;
另请注意,在设置状态后立即调用console.log("Updated features list", newFeatures,e.target.checked)
不会显示更新的状态,因为设置状态是异步的。
【讨论】:
【参考方案2】:问题出在updateFeaturesList
,你直接在listFeatures[ idx ].checked = e.target.checked
这一行改变状态,状态引用保持不变,所以react不知道它是否应该重新渲染。
您可以做的是在更改状态之前复制状态:
const updateFeaturesList = ( e,idx ) =>
const newFeatures = [...listFeatures];
newFeatures[ idx ].checked = e.target.checked
setListFeatures( newFeatures )
console.log( "Updated features list",newFeatures,e.target.checked )
【讨论】:
上帝保佑你兄弟!你救了我一整天!以上是关于数组状态更新后反应不重新渲染的主要内容,如果未能解决你的问题,请参考以下文章