react-rxjs icon indicating copy to clipboard operation
react-rxjs copied to clipboard

To create an operator that ignores the default value emission

Open Jesus-Adaptive opened this issue 8 months ago • 1 comments

Hello,

I have found a case where it would be interesting to add a native helper method to the @react-rxjs library in order to allow emissions from a State but to ignore the default one.

The idea is to use it as follows:

// state.ts - common states module file
const jedisByFilmId$ = state((filmId: string) =>
  requestJedis$.pipe(
    filter(character => character.filmId === filmId),
    toArray(),
  ),
  []
)

// JedisName.tsx - jedis names component
const firstMovieJedisNames$ = jedisByFilmId$('first-movie-uuid').pipe(
  ignoreDefaultEmission(),
  map((jedis) => jedis.name)
)

const JedisNames = () => {
  // component suspended in the closest Subscribe boundary
  // rather than requiring to handle default states 🥇
  const names = useStateObservable(firstMovieJedisNames$)

  return (<List>{names}</List>)
}

The idea is to not to emit an empty array and avoid hacks or initial states to handle the situation.


Of course, we can prevent this by splitting the root state in one state + another state that implements the default value for another use case. But in that case we need a separate root state that avoids implementing a default value.

const requestJedisByFilmId$ = state((filmId: string) =>
  requestJedis$.pipe(
    filter(character => character.filmId === filmId),
    toArray(),
  )
)

const jedisByFilmId$ = state((filmId: string) => requestJedisByFilm$(filmId), [])

// another module
const firstMovieJedisNames$ = requestJedisByFilmId$('first-movie-uuid').pipe(
  map((jedis) => jedis.name)
)

I'm happy to create a PR - let me know if it makes sense to include the operator in the library.

Jesús

Jesus-Adaptive avatar May 07 '25 06:05 Jesus-Adaptive

Hey @Jesus-Adaptive 👋

If I'm not wrong, any operator that does this would be hacky in one way or another.... From the perspective of the operator, it's subscribing to an Observable that emits values.

I'm guessing the a possible way to detect it would be by skipping the value that comes synchronously and waiting for the next value, but that wouldn't work for states that were already alive and that have already solved the first non-default value.

Did you have something else in mind?

At the moment the workaround would be as you say, to create a root state without default value and then put a default value in a separate one.

Another solution I'm thinking, but that requires an API change, is to have a way of transforming a DefaultStateObservable into a StateObservable (and maybe the other way around as well?), something along the lines of

// state.ts - common states module file
const jedisByFilmId$ = state((filmId: string) =>
  requestJedis$.pipe(
    filter(character => character.filmId === filmId),
    toArray(),
  ),
  []
)

// JedisName.tsx - jedis names component
const firstMovieJedisNames$ = jedisByFilmId$.withoutDefault('first-movie-uuid').pipe(
  ignoreDefaultEmission(),
  map((jedis) => jedis.name)
)

Now this would need a deeper discussion, and a better name 🙈 I just quickly thought this. Also not sure if it's worth increasing the API surface for something that has a workaround...

voliva avatar May 07 '25 13:05 voliva