Shopify / react-native-skia

High-performance React Native Graphics using Skia
https://shopify.github.io/react-native-skia
MIT License
6.97k stars 448 forks source link

How can I update Path without rerendering #2638

Open doublelam opened 1 month ago

doublelam commented 1 month ago

Description

const [path, setPath] = useState<SkPath>(Skia.Path.Make());

const panGesture = useMemo(
    () =>
      Gesture.Pan()
        .onBegin(e => {
          'worklet';

          const coords = getRelativeCoords(viewRef as any, e.absoluteX, e.absoluteY);
          path.moveTo(coords?.x||0, coords?.y||0)
        })
        .onUpdate(e => {
          'worklet';

          const coords = getRelativeCoords(viewRef as any, e.absoluteX, e.absoluteY);
          path.lineTo(coords?.x||0, coords?.y||0);
        })
    [],
  );

return (
    <GestureDetector gesture={panGesture}>
      <View ref={viewRef} style={styles.canvas}>
        <Canvas style={{flex: 1}}>
          {/* Drawing path */}
            <Path
              path={path}
              // style="stroke"
              color={strokeColor}
              stroke={{width: typeof strokeWidth === 'number' ? strokeWidth : strokeWidth.value}}
            />
        </Canvas>
      </View>
    </GestureDetector>
  );

it doesn't work. how can I change Path without rerendering?

Version

1.3.11

Steps to reproduce

Above code

Snack, code example, screenshot, or link to a repository

no

mrEuler commented 1 month ago

@doublelam Use sharedValue if you don't want to rerender entire screen:

const currentPath = useSharedValue(Skia.Path.Make());
const panGesture = useMemo(
    () =>
      Gesture.Pan()
        .onBegin(e => {
          'worklet';
          currentPath.modify((v) => {
                const coords = getRelativeCoords(viewRef as any, e.absoluteX, e.absoluteY);

                v.lineTo(coords.x || 0, coords.y || 0);
                return v;
            });
        })
        .onUpdate(e => {
          'worklet';

          const coords = getRelativeCoords(viewRef as any, e.absoluteX, e.absoluteY);
          currentPath.modify((v) => {
                const coords = getRelativeCoords(viewRef as any, e.absoluteX, e.absoluteY);

                v.lineTo(coords.x || 0, coords.y || 0);
                return v;
            });       
          })
    [],
  );
..... // next code stays same
mrEuler commented 1 month ago

@wcandillon issue can be closed

doublelam commented 1 month ago

Ok now it works, but I need to use derived value or it does not work

 const derived = useDerivedValue(() => {
  return pathSharedVal.value.toSVGString()
});

Thank you!