Skip to content

Simplify shared value vectors usage #1337

@terrysahaidak

Description

@terrysahaidak

Description

When you working with transforms, there is a concept that is really handy - Vectors.
Vectors are basically

interface Vector {
  x: Animated.SharedValue<number>,
  y: Animated.SharedValue<number>,
}

But also vectors can be created on UI Thread which makes them

interface Vector {
  x: number,
  y: number,
}

Caveats

This might be handy not for everyone, but still, I find it really useful. The possibility to access .value and get undefined not that great.

Motivation

I created an interface to do some math with vectors where you can pass both types and it will figure it out. But the only problem - then it’s easy to forget to access .value when it’s a shared value vector or you can do it on a regular vector which is not holding shared values and get a crash or undefined.

That’s why I went with the approach where you need to access .value even though it’s not a shared value.

You can find the implementation here:
wcandillon/react-native-redash#373

But still, with complex code, it looks kinda ugly - too many of those .value, because we now have two values for each thing - x and y.

So I thought we can use kinda getter/setter for each property, so every time you access vector.x or vector.y - it actually reads the value of some shared value we have under the hood.

But it doesn’t work because seems like getters are stripped out when we capture objects with them.

Code example

This code logs:

Getter false
Getter false
Mapper {"getter": 0, "sv": 0}
Mapper {"getter": 0, "sv": 0}
Setter false
Mapper {"getter": 0, "sv": 100}
  const useSharedValueTest = (value) => {
    const _sv = useSharedValue(value);

    const obj = {
      _sv,
    };

    function get() {
      'worklet';
      console.log('Getter', _WORKLET);
      return _sv.value;
    }

    function set(nextValue) {
      'worklet';
      console.log('Setter', _WORKLET);
      _sv.value = nextValue;
    }

    Object.defineProperty(obj, 'x', {
      get,
      set,
    });

    return obj;
  };

  const vector = useSharedValueTest(0);

  setTimeout(() => {
    runOnUI(() => {
      vector.x = 100;
    })();
  }, 1000);

  useAnimatedStyle(() => {
    console.log('Mapper', {
      sv: vector._sv.value,
      getter: vector.x,
    });

    return {};
  }, []);

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions