簡體   English   中英

調用 setState 時組件重新渲染

[英]Component re-renders when setState called

反應原生 PanResponder 可拖動被 setState 中斷

我有一個 state 變量來跟蹤秒數

const [seconds, setSeconds] = useState(0)
useEffect(() => {
      const interval = setInterval(() => {
        if (seconds > 59) {
          setSeconds(0)
        } else {
          setSeconds((seconds) => seconds + 1)
        }
      }, 1000)
    
    return () => clearInterval(interval)
 }, [seconds])

我也在使用可拖動的平移響應器

import React, { useState, useRef, ReactNode } from 'react'
import {
  StyleSheet,
  Animated,
  PanResponder,
  PanResponderGestureState,
  Text
} from 'react-native'

const Draggable = (props) => {
    const { draggable, isDropZone, moveToDropArea } = props
    const [showDraggable, setshowDraggable] = useState(true)
    const pan = useRef<Animated.AnimatedValueXY>(new Animated.ValueXY()).current
    const panResponder = PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderMove: Animated.event([
        null,
        {
          dx: pan.x,
          dy: pan.y,
        },
      ]),
      onPanResponderRelease: (e, gesture) => {
        if (isDropZone(gesture)) {
          setshowDraggable(false)
          moveToDropArea()
        } else {
          Animated.spring(pan, {
            toValue: { x: 0, y: 0 },
            useNativeDriver: false,
          }).start()
        }
        pan.flattenOffset()
      },
    })
      return (
        <Animated.View {...panResponder.panHandlers} style={[pan.getLayout()]}>
          <Text>{seconds}</Text>
        </Animated.View>
      )
  }

當我嘗試拖動可拖動對象時,它會移動,但是當 state 更新組件時,組件會重新渲染,並且 Draggable 項目會回到原來的位置。

如何防止這種情況?

提前致謝。

嘗試像這樣編寫你的 useEffect 鈎子:

useEffect(() => {
    const interval = setInterval(() => {
        setSeconds(currentSeconds => currentSeconds > 59 ? 0 : currentSeconds + 1);
    }, 1000);
    
    return () => clearInterval(interval);
}, []);

這樣它就不會在每秒鍾的 state 變化時觸發。

但是,更改 state 仍會使您的組件重新渲染。 如果你想防止重新渲染,你應該使用 useRef 而不是 useState。

const seconds = useRef(0);

useEffect(() => {
    const interval = setInterval(() => {
        seconds.current = seconds.current > 59 ? 0 : seconds.current + 1;
    }, 1000);

    return () => clearInterval(interval);
}, [seconds]);

console.log(seconds.current); // will log the last saved number of seconds before the last re-render

但是如果你需要顯示秒的變化,你需要你的組件在秒 state 變化時重新渲染。 在這種情況下,我建議您將滾動邏輯分離到另一個(可能是父)組件,這樣它就不會在由秒的 state 更改引起的重新渲染時被重置。

在 useEffect 鈎子的第二個參數中傳遞空數組。

useEffect hook 在組件掛載到 dom 時運行回調 function,類似於 class 組件中的 componentDidMount 生命周期方法。

setInterval function 每隔一秒運行一次 setSeconds 方法。

在 useEffect 鈎子中,我們返回一個帶有計時器參數的 clearInterval function,因此當組件從 dom 卸載時,setInterval function 會停止,這類似於 componentWillUnmount 方法。

空數組將在掛載時運行 useEffect,在其整個生命周期中保持沉默。

useEffect(() => {
      const interval = setInterval(() => {
        if (seconds > 59) {
          setSeconds(0)
        } else {
          setSeconds((seconds) => seconds + 1)
        }
      }, 1000)
    return () => clearInterval(interval)
 },[])

暫無
暫無

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

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