skip to Main Content

Boolean inside useRef is not giving correct value, and it is always false in React/React native. Even if the keyboard is present isKeyboardShown inside keyboardDissmissPanResponder = useRef is always false

const isKeyboardShown = keyboardState?.isKeyboardShown ?? false;

const keyboardDissmissPanResponder = useRef(
  PanResponder.create({
    onMoveShouldSetPanResponderCapture: (_e, gestureState) => {
      const isHorizonSwipe = Math.abs(gestureState.dx) > Math.abs(gestureState.dy);
      return isHorizonSwipe && isKeyboardShown;
    },
    onPanResponderGrant: Keyboard.dismiss,
  }),
).current;

How can I fix it? If someone knows what went wrong then please let me know. Thank you

2

Answers


  1. I’d recommend using state, that code will only run once. isKeyboardShown will never change value.

    If you make it a state then the value will always be updated, something like this:

    const [isKeyboardShown, setIsKeyboardShown] = useState(false);
    
    useEffect(() => {
       setIsKeyboardShown(keyboardState?.isKeyboardShown ?? false);
    }, [keyboardState]);
    

    I’m supposing that the keyboardState is an actual state.

    Login or Signup to reply.
  2. isKeyboardShown is always false or never updates because it’s a stale Javascript closure over it in the onMoveShouldSetPanResponderCapture callback handler. The useRef is initially set to the value passed to it, the PanResponder object, and that ref’s initial current value is saved to keyboardDissmissPanResponder.

    From what I can understand it seems you really just want to provide a stable PanResponder object. Use the useMemo hook to create the stable reference with a dependency on the keyboardState reference. Each time the keyboardState reference updates, a new PanResponder object is created and returned for use in the UI.

    Example:

    const keyboardDismissPanResponder = React.useMemo(() => {
      const isKeyboardShown = keyboardState?.isKeyboardShown ?? false;
    
      return PanResponder.create({
        onMoveShouldSetPanResponderCapture: (_e, ({ dx, dy })) => {
          const isHorizonSwipe = Math.abs(dx) > Math.abs(dy);
              
          return isHorizonSwipe && isKeyboardShown;
        },
        onPanResponderGrant: Keyboard.dismiss,
      }),
    }, [keyboardState]);
    

    In some cases where consumers internalize the handlers and don’t react to new instances you may need to take a slightly different approach. Use a React ref to cache the current keyboardState value so the ref can be referenced in the PanResponder handlers. This removes keyboardState as an external dependency for the PanResponder memoization.

    Example:

    const keyboardStateRef = useRef(keyboardState);
    
    React.useEffect(() => {
      keyboardStateRef.current = keyboardState;
    }, [keyboardState]);
    
    const keyboardDismissPanResponder = React.useMemo(() => {
      return PanResponder.create({
        onMoveShouldSetPanResponderCapture: (_e, ({ dx, dy })) => {
          const isKeyboardShown = keyboardStateRef.current?.isKeyboardShown ?? false;
          const isHorizonSwipe = Math.abs(dx) > Math.abs(dy);
              
          return isHorizonSwipe && isKeyboardShown;
        },
        onPanResponderGrant: Keyboard.dismiss,
      }),
    }, []);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search