代码之家  ›  专栏  ›  技术社区  ›  Evanss

未在onPanResponderRelease中读取React Native的onPanResponderGrant中的设置状态

  •  0
  • Evanss  · 技术社区  · 4 年前

    useState 在里面 onPanResponderMove . 页面加载时 OnPanResponder移动 0 .

    但是当我点击 TouchableOpacity foo 静像注销 而不是它的新价值。

    export default function App() {
      const [foo, setFoo] = React.useState(0);
    
      const panResponder = React.useRef(
        PanResponder.create({
          onStartShouldSetPanResponder: (evt, gestureState) => true,
          onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
          onMoveShouldSetPanResponder: (evt, gestureState) => true,
          onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
          onPanResponderGrant: (evt, gestureState) => {},
          onPanResponderMove: (evt, gestureState) => {
            console.log(foo); // This is always 0
          },
          onPanResponderTerminationRequest: (evt, gestureState) => true,
          onPanResponderRelease: (evt, gestureState) => {},
          onPanResponderTerminate: (evt, gestureState) => {},
          onShouldBlockNativeResponder: (evt, gestureState) => {
            return true;
          },
        })
      ).current;
    
      return (
        <View style={{ paddingTop: 200 }}>
          <TouchableOpacity onPress={() => setFoo(foo + 1)}>
            <Text>Foo = {foo}</Text>
          </TouchableOpacity>
          <View
            {...panResponder.panHandlers}
            style={{ marginTop: 200, backgroundColor: "grey", padding: 100 }}
          >
            <Text>Text for pan responder</Text>
          </View>
        </View>
      );
    }
    
    0 回复  |  直到 4 年前
        1
  •  4
  •   LonelyCpp    4 年前

    pan响应程序取决于值“foo”。 useRef 在这里可不是个好选择。你应该把它换成 useMemo

    const panResponder = useMemo(
         () => PanResponder.create({
           [...]
            onPanResponderMove: (evt, gestureState) => {
              console.log(foo); // This is now updated
            },
           [...]
          }),
         [foo] // dependency list
      );
    
        2
  •  2
  •   Leo    4 年前

    PanResponder 一次是和 foo 那时候你有的。但是每一个 setFoo 从useState钩子。PanResponder不会知道那个新的foo。这是由于useRef是如何工作的,因为它为您提供了贯穿整个组件生命周期的可变对象。(这在react文档中进行了解释 here )

    (您可以在这篇文章中讨论这个问题和一个简单的解决方案 sandbox

    在您的例子中,最简单的解决方案是用新的

    export default function App() {
      const [foo, setFoo] = React.useState(0);
    
      const panResponder = React.useRef(
        PanResponder.create({
          onStartShouldSetPanResponder: (evt, gestureState) => true,
          onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
          onMoveShouldSetPanResponder: (evt, gestureState) => true,
          onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
          onPanResponderGrant: (evt, gestureState) => {},
          onPanResponderMove: (evt, gestureState) => {
            console.log(foo);
          },
          onPanResponderTerminationRequest: (evt, gestureState) => true,
          onPanResponderRelease: (evt, gestureState) => {},
          onPanResponderTerminate: (evt, gestureState) => {},
          onShouldBlockNativeResponder: (evt, gestureState) => {
            return true;
          },
        })
      ).current;
    
      // update the onPanResponderMove with the new foo
      panResponder.onPanResponderMove = (evt, gestureState) => {
         console.log(foo);
      },
    
      return (
        <View style={{ paddingTop: 200 }}>
          <TouchableOpacity onPress={() => setFoo(foo + 1)}>
            <Text>Foo = {foo}</Text>
          </TouchableOpacity>
          <View
            {...panResponder.panHandlers}
            style={{ marginTop: 200, backgroundColor: "grey", padding: 100 }}
          >
            <Text>Text for pan responder</Text>
          </View>
        </View>
      );
    }
    

    注意

    如果某个可变的组件取决于您的组件状态,请务必格外小心。如果真的有必要,用getter和setter编写一个合适的类或对象通常是个好主意。例如:

    
    
    const createPanResponder = (foo) => {
    
      let _foo = foo;
    
      const setFoo = foo => _foo = foo;
      const getFoo = () => _foo;
    
      return {
         getFoo,
         setFoo,
         onPanResponderMove: (evt, gestureState) => {
            console.log(getFoo());
          },
         ...allYourOtherFunctions
      }
    
    }
    
    const App = () => {
      const [foo, setFoo] = React.useState(0);
      const panResponder = useRef(createPanResponder(foo)).current;
      panResponder.setFoo(foo);
    
      return ( ... )
    
    }
    
    
        3
  •  1
  •   Juan Marco    4 年前

    foo 试图更新现有状态。相反,传递前一个状态并相应地更新它( functional update ). 这样地:

    <TouchableOpacity onPress={() => setFoo(f =>  f + 1)}>
      <Text>Foo = {foo}</Text>
    </TouchableOpacity>
    

    使当前值 可在 onPanResponderMove 处理程序。创建 ref .

    根据文件:

    ref对象是一个通用容器,其 current 属性是可变的,可以保存任何值

    const [foo, setFoo] = React.useState(0);
    
    const fooRef = React.useRef()
    React.useEffect(() => {
      fooRef.current = foo
    },[foo])
    

    然后在里面 OnPanResponder移动 处理程序您可以访问我们之前设置的ref的当前值:

    onPanResponderMove: (evt, gestureState) => {
      console.log('fooRef', fooRef.current)
      alert(JSON.stringify(fooRef))
    },
    

    here

    here

        4
  •  0
  •   Evanss    4 年前

    useEffect 您可以创建一个新的 PanResponder 什么时候 foo 变化。不过,我不知道这是如何表现。

    export default function App() {
      const [foo, setFoo] = React.useState(0);
    
      const pan = PanResponder.create({
        onStartShouldSetPanResponder: (evt, gestureState) => true,
        onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
        onMoveShouldSetPanResponder: (evt, gestureState) => true,
        onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
        onPanResponderGrant: (evt, gestureState) => {},
        onPanResponderMove: (evt, gestureState) => {
          console.log(foo); // This is always 0
        },
        onPanResponderTerminationRequest: (evt, gestureState) => true,
        onPanResponderRelease: (evt, gestureState) => {},
        onPanResponderTerminate: (evt, gestureState) => {},
        onShouldBlockNativeResponder: (evt, gestureState) => {
          return true;
        },
      });
    
      const [panResponder, setPanResponder] = React.useState(pan);
    
      useEffect(() => {
        setPanResponder(pan);
      }, [foo]);
    
      return (
        <View style={{ paddingTop: 200 }}>
          <TouchableOpacity onPress={() => setFoo(foo + 1)}>
            <Text>Foo = {foo}</Text>
          </TouchableOpacity>
          <View
            {...panResponder.panHandlers}
            style={{ marginTop: 200, backgroundColor: "grey", padding: 100 }}
          >
            <Text>Text for pan responder</Text>
          </View>
        </View>
      );
    }