动作-Action

Action is a simplified Rx-inspired reactive stream focused on animation.

action是一个简化的rx风格的专注于动画的数据流

popmotion提供的动画其实都是一个封装过的action

引入

import { action } from 'popmotion';

使用

工厂

action工厂需要传入一个初始化init方法,我们为该方法提供了一个包含了 update complete error方法的对象参数, 你可以自行选择是否使用

action(({ update, complete, error }) => {
  update(1);
});

初始化

工厂会返回一个start方法,该方法同样接受一个包含update complete error的对象。

当调用start方法,工厂就会初始化一个实例,多次调用,就会产生多个实例。

init方法里面通过update输出的内容,都会在start里面的update里面接受到

所以下面的例子,就会每50ms输出一个不断增长的数字

const foo = action(({ update }) => {
  let i = 0;
  setInterval(() => update(i++), 50);
});

foo.start({
  update: (v) => console.log(v)
});  // 0, 1, 2, ...

如果只给start传一个方法,那么这个方法就被当成update

foo.start((v) => console.log(v)); // 0, 1, 2...

update可以多次调用,那么在start里面的update也会多次输出, complete error方法只能调用一次,并且不需要传参,这个很好理解

const foo = action(({ update, complete }) => {
  let i = 0;
  setInterval(() => {
    update(i++);
    if (i === 10) complete();
  }, 50);
});

foo.start({
  update: (v) => console.log(v), // ...8, 9, 10
  complete: () => console.log('complete!')
});

接口

init方法可以自定义返回的API

const foo = action(({ update }) => {
  const interval = setInterval(() => update('ping!'), 100);

  return {
    stop: () => clearInterval(interval)
  };
});

const bar = foo.start(console.log);
setTimeout(() => bar.stop(), 1000);

修改值

action是允许基于数据流进行链式调用的,这就说明我们可以对基本动作进行修改和操作。

const foo = action(({ update }) => {
  let i = 0;
  setInterval(() => update(i++), 50);
});

const lessThanTen = (v) => v < 10;
const log = (v) => console.log(v);

foo.start(log); // ...8, 9, 10, 11...
foo.while(lessThanTen).start(log); // ...8, 9

方法

pipe

pipe(...funcs: (v: any) => any)

可以传入多个方法对update输出的数据流进行操作

const init = ({ update }) => update(10);
const double = (v) => v * 2;
const px = (v) => v + 'px';

action(init)
  .pipe(double, px)
  .start((v) => console.log(v)); // '20px'

start

start(update: (v: any) => void)
start({
  complete? () => void,
  error?: (err: any) => void,
  update?: (v: any) => void
})
start(reaction)

调用了start方法之后,就会运行init方法,并返回自定义的API

所有的API至少有一个stop方法,你可以在返回的API重写

while

while(predicate: (v: any) => boolean)

过滤数据,只有满足条件的才会往后传,否则就会调用complete

let latest = 0;

const init = ({ update }) => {
  let i = latest;
  setInterval(() => update(i++), 50);
};

action(init)
  .while((v) => v < 10)
  .start({
    update: (v) => latest = v,
    complete: () => console.log(v) // 9
  });