Call React Native code when reanimated SharedValue changes

Viewed 1943

I have a reanimated ReadOnly<SharedValue<boolean>> that is derived from another SharedValue:

  const solidHeader = useDerivedValue(() => {
    return top.value <= -(height / 2);
  });

I would like to call a RN function (non-reanimated) when solidHeader.value changes. Concretely I would like to update my react-navigation's header transparency:

// This doesn't get called when `solidHeader.value` is updated in reanimated's thread
useEffect(() => {
  navigation.setOptions({headerTransparent: !solidHeader.value});
}, [solidHeader.value]);

I have tried the following which "seems" to be the correct way, but then I get the error

Reanimated: Animated.call node args should be an array with elements of type AnimatedNode. One or more of them are not AnimatedNodes
    useCode(() => {
      return call([solidHeader], (solidHeader) => {
        console.warn(solidHeader);
        navigation.setOptions({
          headerTransparent: !solidHeader,
        });
      });
    }, [solidHeader]);

Is what I'm achieving even possible?

2 Answers

EDIT: see the accepted answer.

So this is the hack that I ended up doing: I think the reason why this is so janky is because Reanimated intentionally avoids communicating over the JS/Reanimated threads, so I have to "poll" on the JS side to "depend" on changes on the Reanimated side:

  // top is a SharedValue
  const { top, height } = useHeaderMeasurements();
  const [headerTransparent, setHeaderTransparent] = useState(
    top.value >= -(height / 2)
  );

  useEffect(() => {
    // Poll 60FPS and update RN state
    const check = setInterval(() => {
      setHeaderTransparent(top.value >= -(height / 2));
    }, 1000 / 60);
    return () => clearInterval(check);
  }, [top]);

  useEffect(() => {
    navigation.setOptions({ headerTransparent });
  }, [navigation, headerTransparent]);

For context:

  • useHeaderMeasurements is from react-native-collapsible-tab-view which uses Reanimated V2 under the hood
  • navigation.setOptions is from react-navigation, which requires us to set headerTransparent imperatively on the RN side when we're inside a Screen

I think useCode is for reanimated 1 and useSharedValue is for reanimated 2. follow the doc: Try useAnimatedReaction

Related