Ore*_*lus 2 reactjs react-native
我正在努力useMemo(或React.memo)优化某些组件的渲染。
我有一个我无法解释的问题。
我有以下代码:
[...]
const [ cards, setCards ] = useState<Card[]>([])
function addCard(){
setCards([...cards, {name: 'card-' + cards.length, counter: 0, type: 'memo'}])
}
function onPressCard(index: number){
cards[index].counter += 1
setCards([...cards])
}
return (
[...]
{
cards.map((x, index) =>
<Card key={index} {...x} onPress={() => onPressCard(index)}/>
}
[...]
)
Run Code Online (Sandbox Code Playgroud)
和卡定义为
const Card: FC<CardProps> = function({ name, counter, onPress }){
const counterRef = useRef(0)
const item = useMemo(() => {
counterRef.current +=1
return (
<RectButton onPress={onPress} style={[styles.card, { backgroundColor: 'lightcoral' }]}>
<Text style={styles.text}>{ name }</Text>
<Text style={styles.counter}> { `counter ${counter}` }</Text>
<Text style={styles.counter}>{ `render: ${counterRef.current}`}</Text>
</RectButton>
)
}, [name, counter])
return item
}
Run Code Online (Sandbox Code Playgroud)
为什么当我按列表中的一项(最后一项除外)时,以下所有项都消失了?

编辑:卡片定义为
const areEqual = function(prevProps: Card, nextProps: Card){
return (
(prevProps.name === nextProps.name) &&
(prevProps.counter === nextProps.counter)
)
}
const Card = React.memo<CardProps>(({ name, counter, onPress }) => {
const counterRef = useRef(0)
counterRef.current +=1
return (
<RectButton onPress={onPress} style={[styles.card, { backgroundColor: 'lightcoral' }]}>
<Text style={styles.text}>{ name }</Text>
<Text style={styles.counter}> { `counter ${counter}` }</Text>
<Text style={styles.counter}>{ `render: ${counterRef.current}`}</Text>
</RectButton>
)
}, areEqual)
Run Code Online (Sandbox Code Playgroud)
问题是备忘的组件包含对的旧版本的引用onPress。该旧onPress版本cards在关闭时具有旧版本。因此,点击该按钮将调用旧功能,该功能会根据该旧状态更新父级的状态,并且该旧状态中包含的项较少。
解决此问题的一种方法是使用setCards的功能版本,以便使更新基于最新状态。另外,我更新了代码以不再更改旧卡:
function onPressCard(index: number){
setCards(oldCards => {
const newCards = [...oldCards];
newCards[index] = {...oldCards[index]};
newCards[index].counter += 1;
return newCards;
})
}
Run Code Online (Sandbox Code Playgroud)
另一个选择是将onPress添加到useMemo的条件中,但是由于onPress函数一直在变化,因此最终不会真正从备忘录中获得任何收益。如果使用useCallback记住onPress本身,则可以改进此方法:
const onPressCard = useCallback((index: number) => {
cards[index].counter += 1;
setCards([...cards]);
}, [cards])
// ...
const item = useMemo(() => {
counterRef.current +=1
return ( /* jsx omitted for brevity */ )
}, [name, counter, onPress])
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
88 次 |
| 最近记录: |