子组件不会在道具更改时重新渲染
Child component not rerendered on prop change
在以下代码中,我希望 OfferList
在我向商店添加商品时重新呈现。 OfferList
本身不是 observable,但 offer 数组作为 prop 传递。
export const MerchantScreen: FC = observer(() => {
const { merchantStore } = useStores()
return (
<View>
<OfferList data={merchantStore.offers} />
<View>
<Button title={"New Offer"} onPress={() => merchantStore.addOffer()}/>
</View>
</View>
)
})
export const OfferList: FC<OfferListProps> = ({ data }: OfferListProps) => {
const renderItem = (offer: ListRenderItemInfo<any>) => {
return (
<Text>{offer.name}</Text>
)
}
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
)
}
我使用 Mobx 状态树。 merchantStore.addOffer()
目前所做的只是将另一个报价项目推入数组。
我的尝试/发现:
当我从 MerchantScreen
中的商店阅读时,例如通过添加
<Text>{ merchantStore.offers.toString() }</Text>
,OfferList
也会更新。我怀疑直接在父组件中从商店读取也会强制重新渲染子组件。
我在这里偶然发现了一些答案,这些答案表明 FlatList renderItems 中缺少 key
属性可能是问题所在。尝试使用 key={item.id}
无济于事。另外,如您所见,我使用了 FlatList 的 keyExtractor 道具。
另一个答案建议像这样将本地状态引入组件:
export const OfferList: FC<OfferListProps> = ({ data }: OfferListProps) => {
const [offers, setOfferss] = useState()
useEffect(() => {
setOffers(data)
}, [data])
const renderItem = (offer: ListRenderItemInfo<any>) => {
return (
<Text>{offer.name}</Text>
)
}
return (
<FlatList
data={offers}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
)
}
这行不通,我的直觉是这不是它的完成方式。
如您所见,我的 MerchantScreen
父组件是可观察的,而我的子组件 OfferList
不是。按照我的预期,我的父组件上的 observer
应该足够了。父组件应该已经检测到商店中的变化并重新呈现。子组件本身甚至不使用商店。
总的来说,手头的问题似乎很微不足道,所以我想我只是错过了一个重要的细节。
MobX 只跟踪观察者组件访问的数据,如果它们被渲染直接访问的话,所以如果你想对每个 offers
做出反应,你需要在某个地方访问它们。当你尝试 merchantStore.offers.toString()
时,你有点做了,这就是它起作用的原因。
所以首先你需要让 OfferList
成为 observer
.
但是你有 FlatList
,它是本机组件,你不能将它变成 observer
。您可以做的是访问 OfferList
中的每个 offers
项目(基本上只是为了订阅更新),就像 data={offers.slice()}
甚至更好地使用 MobX 辅助方法 toJS
data={toJS(offers)}
根据您的用例,您可能还想在 renderItem
回调中使用 <Observer>
:
const renderItem = (offer: ListRenderItemInfo<any>) => {
return (
<Observer>{() => <Text>{offer.name}</Text>}</Observer>
)
}
在以下代码中,我希望 OfferList
在我向商店添加商品时重新呈现。 OfferList
本身不是 observable,但 offer 数组作为 prop 传递。
export const MerchantScreen: FC = observer(() => {
const { merchantStore } = useStores()
return (
<View>
<OfferList data={merchantStore.offers} />
<View>
<Button title={"New Offer"} onPress={() => merchantStore.addOffer()}/>
</View>
</View>
)
})
export const OfferList: FC<OfferListProps> = ({ data }: OfferListProps) => {
const renderItem = (offer: ListRenderItemInfo<any>) => {
return (
<Text>{offer.name}</Text>
)
}
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
)
}
我使用 Mobx 状态树。 merchantStore.addOffer()
目前所做的只是将另一个报价项目推入数组。
我的尝试/发现:
当我从 MerchantScreen
中的商店阅读时,例如通过添加
<Text>{ merchantStore.offers.toString() }</Text>
,OfferList
也会更新。我怀疑直接在父组件中从商店读取也会强制重新渲染子组件。
我在这里偶然发现了一些答案,这些答案表明 FlatList renderItems 中缺少 key
属性可能是问题所在。尝试使用 key={item.id}
无济于事。另外,如您所见,我使用了 FlatList 的 keyExtractor 道具。
另一个答案建议像这样将本地状态引入组件:
export const OfferList: FC<OfferListProps> = ({ data }: OfferListProps) => {
const [offers, setOfferss] = useState()
useEffect(() => {
setOffers(data)
}, [data])
const renderItem = (offer: ListRenderItemInfo<any>) => {
return (
<Text>{offer.name}</Text>
)
}
return (
<FlatList
data={offers}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
)
}
这行不通,我的直觉是这不是它的完成方式。
如您所见,我的 MerchantScreen
父组件是可观察的,而我的子组件 OfferList
不是。按照我的预期,我的父组件上的 observer
应该足够了。父组件应该已经检测到商店中的变化并重新呈现。子组件本身甚至不使用商店。
总的来说,手头的问题似乎很微不足道,所以我想我只是错过了一个重要的细节。
MobX 只跟踪观察者组件访问的数据,如果它们被渲染直接访问的话,所以如果你想对每个 offers
做出反应,你需要在某个地方访问它们。当你尝试 merchantStore.offers.toString()
时,你有点做了,这就是它起作用的原因。
所以首先你需要让 OfferList
成为 observer
.
但是你有 FlatList
,它是本机组件,你不能将它变成 observer
。您可以做的是访问 OfferList
中的每个 offers
项目(基本上只是为了订阅更新),就像 data={offers.slice()}
甚至更好地使用 MobX 辅助方法 toJS
data={toJS(offers)}
根据您的用例,您可能还想在 renderItem
回调中使用 <Observer>
:
const renderItem = (offer: ListRenderItemInfo<any>) => {
return (
<Observer>{() => <Text>{offer.name}</Text>}</Observer>
)
}