簡體   English   中英

功能組件隨着useMemo / React.memo消失

[英]Functional components disappearing with useMemo / React.memo

我試圖繞過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)}/>
    }
    [...]
)

定義為


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
}

為什么當我按列表中的一項(最后一項除外)時,以下所有項都消失了? 在此處輸入圖片說明

編輯: 卡片定義為

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)

問題在於,記憶化組件包含對onPress的舊版本的引用。 那個舊的onPress封閉了一個舊版本的cards 因此,點擊該按鈕將調用舊功能,該功能會根據該舊狀態更新父級的狀態,並且該舊狀態中包含的項較少。

解決此問題的一種方法是使用setCards的功能版本,以便使更新基於最新狀態。 另外,我更新了代碼以不再更改舊卡:

function onPressCard(index: number){
  setCards(oldCards => {
    const newCards = [...oldCards];
    newCards[index] = {...oldCards[index]};
    newCards[index].counter += 1;
    return newCards;
  })
}

另一個選擇是將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])    

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM