animatedjs/animated

Calculated values

Opened this issue · 3 comments

What are you guys thinking about calculated values? Something like Behaviors in FRP terms or spreadsheet-like dataflow.

Main question is why do we need them?

Ok - let's explain we have transitions between scenes, and main value for all transition is progress - this is value changed by time for 0 to 1. In scene we want to change text opacity and some position.

const Scene = (width, height, progress) =>
    <View style={{position: "absolute",
                           height: height,
                           width: width,
                           backgroundColor "blue"}}
        <Text style={{fontSize: 16,
                      opacity: progress < 0.5 ? (1 - (progress * 2)) : 0,
                      marginLeft: progress < 0.5 ? (progress * 2 * 250 * -1) : 0}} />
    </View>

But I want to use calculated values, smth like this:

class AnimatedCell {
    constructor() {
        this._subscribers = [];
    }

    push(value) {
       this._subscribers.forEach(next => next.call(null, value));
    }

    subscribe(next) {
       this._subscribers.push(next);
    }
}

const bind = (cell, fn) => {
    const newCell = new AnimatedCell();
    cell.subscribe(val => newCell.push(fn.call(null, val))
}

const bindToAnimated = (cell, initialValue) =>
    const newAnimated = new AnimatedValue(initialValue || 0);
    cell.subscribe(val => newAnimated.setValue(val));
    return newAnimated;
}

And use it in scene:

const Scene = (width, height, progress) => {
    const opacity = bind(progress, progress => progress < 0.5 ? (1 - (progress * 2)) : 0);
    const marginLeft = bind(progress, progress => progress < 0.5 ? (progress * 2 * 250 * -1) : 0);
    return (
    <View style={{position: "absolute",
                           height: height,
                           width: width,
                           backgroundColor "blue"}}
        <Text style={{fontSize: 16,
                          opacity: bindToAnimated(opacity, 1),
                          marginLeft: bindToAnimated(marginLeft, 0)}} />
    </View>
    );
}

Every time when progress is changed, opacity and margin-left recalculated and refresh Animated.
What do you think?

If you guys familiar with ClojureScript you can see it in action on my experiment with react native navigation https://github.com/savelichalex/experiment-navigation-react-native/tree/cell-proposal

gre commented

I also think being able to implement this bind() make Animated more powerful and interesting (myself, I prefer to call it map() but whatever). Also allow to extend Animated in third party library.

I remember we had a discussion here in the past: animatedjs/interactive-docs#5

is this ~ the same topic or am I out of subject?

I think the main problem we evoked, is that it is hard for React Native to implement Animations in an another thread (like in ObjC / Java side) if animated object are not serializable, which is the case when you use newValue = bind(value, aJSFunction) .

Yeah, this is possible to extend in third party library, but maybe we can create smth interesting if it'll be in core. I'm trying to say, that we also can extend behavior of few core methods. For example if Animated.timing get computed value, then they just push on it and update all dependent values.