Home > Mobile >  react-native-really-awesome-button onPress does not update function when state changes
react-native-really-awesome-button onPress does not update function when state changes

Time:11-04

I installed the react-native-really-awesome-button package because it has some really awesome buttons.

Unfortunately, it seems like the onPress handler does not work as intended.

Here is a reproducible demo: https://snack.expo.dev/@anshnanda/awesomebutton-not-working You can clearly see that the onPress function just uses the initial state and is not updated with new state.

It is clear that AwesomeButton is just using the initial state value of num which leads me to think the function is wrapped with useMemo or useCallback (with a likely bug), however, digging through the source code, I couldn't find why this happens.

I tried using onPressIn and onPressOut and those seem to be working fine, except the UX is obviously worse since the user doesn't see the slick animation that I downloaded react-native-really-awesome-button for.

CodePudding user response:

It seems like you are asking for confirmation that it's a bug/issue in the AwesomeButton, and I agree that it is.

The onPress callback is stored in a React ref: (source)

const debouncedPress = useRef(
  debouncedPressTime
    ? debounce(
        (animateProgressEnd: (callback?: any) => void) =>
          onPress(animateProgressEnd), // <-- here
        debouncedPressTime,
        {
          trailing: false,
          leading: true,
        }
      )
    : onPress // <-- here
);

debouncedPress is called in a press handler: (source)

const press = () => {
  actioned.current = true;
  if (progressing.current === true) {
    return;
  }

  if (progress === true) {
    requestAnimationFrame(startProgress);
  }

  debouncedPress.current(animateProgressEnd); // <-- here
};

press is called by the handlePressOut callback: (source)

It's the animateProgressEnd handler that calls the passed onPress function (debouncedPress) though: (source)

const animateProgressEnd = (callback: any) => { // <-- your callback
  if (progress !== true) {
    return;
  }

  if (timeout?.current) {
    clearTimeout(timeout.current);
  }

  requestAnimationFrame(() => {
    animateTiming({
      variable: animatedLoading,
      toValue: 1,
    }).start(() => {
      Animated.parallel([
        animateElastic({
          variable: textOpacity,
          toValue: 1,
        }),
        animateElastic({
          variable: activityOpacity,
          toValue: 0,
        }),
        animateTiming({
          variable: loadingOpacity,
          toValue: 0,
          delay: 100,
        }),
      ]).start(() => {
        animateRelease(() => {
          progressing.current = false;
          callback && callback(); // <-- called here
          onProgressEnd && onProgressEnd();
        });
      });
    });
  });
};

So yes, the React ref debouncedPress is never updated to hold a newer instance of your passed onPress callback handler.

To get around this you can use a React ref in your code to cache the num state and reference this in the printCurrNum handler.

Example:

function App() {
  const [num, setNum] = React.useState(0);
  const [currentValue, setCurrentValue] = React.useState(0);

  const numRef = React.useRef(num); // <-- ref to cache num state
  React.useEffect(() => {           // <-- effect to update cache
    numRef.current = num;
  }, [num]);

  const increment = () => {
    setNum((num) => num   1);
  };

  const printCurrNum = () => {
    console.log(numRef.current);     // <-- reference current value
    setCurrentValue(numRef.current); // <-- reference current value
  };

  return (
    <View style={styles.container}>
      <Text>Current value according to AwesomeButton: {currentValue}</Text>
      <Text>{num}</Text>
      <AwesomeButton onPress={printCurrNum}>
        Update current value with Awesome Button
      </AwesomeButton>
      <Button title="Increment" onPress={increment} />
      <Button
        title="Update current value with native button"
        onPress={printCurrNum}
      />
    </View>
  );
}

https://snack.expo.dev/@drew.w.reese/awesomebutton-not-working

  • Related