state 用作组件中的 props,状态更改不会重新渲染组件
Posted
技术标签:
【中文标题】state 用作组件中的 props,状态更改不会重新渲染组件【英文标题】:State use as props in component, state change will not re-render the component 【发布时间】:2021-04-26 17:40:58 【问题描述】:如果状态改变,React 会重新渲染。那为什么下面的情况不能重新渲染呢?
根据程序行为,我发现
-
当状态改变时,如果该状态直接在组件中使用,会重新渲染。
当状态发生变化时,如果状态被用作子组件中的道具,它不会被重新渲染。
如何直接重新渲染该子组件?
以下程序来自我的代码并进行了一些修改。 更新: SandBox 这是我在沙盒中创建的代码,我尝试模拟我的真实情况
function List(props)
const [fullListValue, setFullListValue] = useState([]); //store data which get from server
const [dropDrowList, setDropDrowList] = useState([]); //store data column value (e.g. data contain "fruit" column, this state will store "apple", "berry", "banana" etc.)
const setAllList = (data) =>
setFullListValue(data);
;
useEffect ( ()=>
//axios call server, use setAllList(data) to save state
,[]
//when fullListValue is updated,
useEffect(() =>
const dropDrowListCopy = [ ['label']: 'ALL', ['value']: 'ALL' ];
//push all "fruit" data in dropDrowListCopy without duplicate
console.log(dropDrowListCopy); //this will show all dropdown I want, i.e. "ALL","apple", "berry", "banana"
setDropDrowList(dropDrowListCopy); //set to dropDrowList, and I expect this step will re-render the SelectionList component, however, it do not
, [fullListValue]);
return (
<div>
<div>
dropDrowList.length <= 1 ? (
'loading' //I add this to re-render the component, but I think this is not a good way to re-render the component
) : (
<SelectionList
itemList=dropDrowList
/>
)
</div>
</div>
);
【问题讨论】:
请在Minimal, Complete, and Reproducible 代码示例中包含所有相关代码。你能分享SectionList
代码吗?也许还有一个更准确的例子来说明你如何更新状态。
codesandbox.io/s/0wff7 这是我在沙箱中创建的代码,我尝试模拟我的真实情况
【参考方案1】:
问题
在SecitonList
中,您将传递的道具存储到状态中,但不会在道具更改时更新状态,从而使您处于陈旧状态。出于这个原因,将 props 存储在本地组件状态中实际上是一种 React 反模式。
解决方案
props 改变时更新状态。
function SelectionList(props)
const [listItem, setListItem] = useState(
props.itemList ? props.itemList : []
);
useEffect(() =>
setListItem(props.itemList);
,
[props.itemList]);
return (
<FormControl>
<Select
renderValue=
props.multiple ? (selected) => fieldDisplay(selected) : null
input=<Input />
>
listItem.map((item) => (
<MenuItem key=item.value value=item>
props.multiple ? (
<Checkbox checked=selectedValue.indexOf(item) > -1 />
) : null
<ListItemText primary=item.label />
</MenuItem>
))
</Select>
</FormControl>
);
解决办法——直接消耗道具
function SelectionList(props)
return (
<FormControl>
<Select
renderValue=
props.multiple ? (selected) => fieldDisplay(selected) : null
input=<Input />
>
props.itemList.map((item) => (
<MenuItem key=item.value value=item>
props.multiple ? (
<Checkbox checked=selectedValue.indexOf(item) > -1 />
) : null
<ListItemText primary=item.label />
</MenuItem>
))
</Select>
</FormControl>
);
【讨论】:
谢谢!换句话说,我只更新父组件中的状态,但在子组件中,状态(从父组件传递)没有更新。于是,bug就出来了。我的理解正确吗? @0o0SkY0o0 或多或少,是的,没错。【参考方案2】:你需要改变这个条件:
dropDrowList.length <= 1
您只为 dropDrowList 分配了 1 个对象,因此它不会呈现 SelectionList。
改为:
dropDrowList.length < 1
应该启用 SelectionList 来呈现。
【讨论】:
dropDrowList.length @0o0SkY0o0 然后在您的 useEffect() (或其他地方)中添加另一个项目,否则由于该条件,它将永远不会呈现。 建议:在 useEfect 中分配数组以具有 2 个值: const dropDrowList = [label: 'ALL', value: 'ALL',label: 'Test', value:'Test' ];这将允许 SelectionList 呈现。以上是关于state 用作组件中的 props,状态更改不会重新渲染组件的主要内容,如果未能解决你的问题,请参考以下文章
React Native入门组件的Props(属性)和State(状态)