sane way to pass/keep a value throwout a long pipe

安稳与你 提交于 2019-12-10 15:43:16

问题


Assuming i have the following rxjs pipe:

start$.pip(
    map((id)=> {}), //I want to save the "id" value to be used in the end of the pipe
    map(...),
    switchMap(...),
    map(...),
    switchMap(...),
    map(...),
    switchMap(...),
    switchMap(...)//I need the original "id" value here
).subscribe()

Is there a way to keep the 'id" value throughout the pip so it can be used at the end of the pipe?

Motivation: It comes often in NGRX effects where i want to use the original payload data of the triggering source action for generating the new action.


回答1:


I think the correct way is to make another closure

const processId = (id) => observableOf(id)
  .pipe(
    map(() => { ... }),
    map(...),
    switchMap(...),
    map(...),
    switchMap(...),
    map(...),
    switchMap(...),
    switchMap(...) // Use id here
  );

const getPipe = () => start$
  .pipe(switchMap(processId));

Storing local variable as a side effect in getPipe is OK, but it can break if start$ Observable emits more values.




回答2:


The way suggested by @René Winkler is the right way for short pipes.

If the pipe is long though it can be tedious and somehow can make the code less readable.

One alternative approach can be to create a function (or method) where you define id as a local variable that you set within the first map so that you can use it at your convenience all along the chain of operators, something like

getLongPipe(id) {
  let _id;
  return start$.pipe(
    map((id)=> {_id = id; ....}), //I want to save the "id" value to be used in the end of the pipe
    map(...),
    switchMap(...),
    map(...),
    switchMap(...),
    map(...),
    switchMap(...),
    switchMap(...)//Here you can use _id
  )
}

getLongPipe(id).subscribe()



回答3:


The closure seems correct, would like to add a detail gotcha, I boiled down to a base case:

Say you want to get to the end of a stream, and based on something that happened earlier, do this or that. So you use the closure pattern, start with a flag of false, and later in the pipe, set it to true. At the end of the pipe, do this or that depending on the flag. Works nicely.

Problem is, after the first time, if that value got set to true, depending on your use (say, an NGRX effect, which is where I ran into this) it'll be true forever (no surprise, the closure persists) unless something else sets it back to the default (false).

Basic form/fix:

stream$ = ( ( my_flag = false ) => {
    return ( otherStream$
        .variousOperators ( ... )
        .do ( x => { 
           my_flag = some_condition_of_x ? true : false
        } )
        .map ( x => my_flag ? a : b )
        .do ( x => {
          my_flag = false; // reset
        } )
        .map ( x => x )
    );
  } ) ();

Had a pretty tricky case involving some NGRX effects that was greatly (greatly) simplified by this.



来源:https://stackoverflow.com/questions/51578014/sane-way-to-pass-keep-a-value-throwout-a-long-pipe

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!