-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Rewriting mapPropsStream with Hooks or new Lifecycle Methods #783
Comments
the author has discontinued support for recompose and recommended react hook as a replacement. |
Understood, and I think that's a fine choice. I'm just not sure how (or even if, given the current state of the hooks API) it would be possible to recreate the functionality of mapPropsStream using hooks. At issue is delaying the component's render from when it receives props to when the observable emits (which may be immediate or not). The current recompose implementation, and the above simplified reimplementation, essentially achieve that by using |
@jameslaneconkling Did you manage to recreate the functionality of mapPropsStream using hooks? I am looking for this |
@gemma-ferreras the solution I've ended up w/ looks like: const useStream = <T, R>(
project: (stream$: Observable<T>) => Observable<R>,
data: T,
): R | undefined => {
const prev = useRef<T>()
const stream$ = useRef(new Subject<T>())
const emit = useRef<R>()
const synchronous = useRef(true)
const [_, rerender] = useState(false)
useLayoutEffect(() => {
const subscription = stream$.current.pipe(project).subscribe({
next: (next) => {
emit.current = next
if (!synchronous.current) {
rerender((prev) => !prev)
}
}
})
stream$.current.next(data)
return () => subscription.unsubscribe()
}, [])
synchronous.current = true
if (prev.current !== data) {
emit.current = undefined
stream$.current.next(data)
}
prev.current = data
synchronous.current = false
return emit.current
} It's a little bit wordier than I'd hoped, but essentially subscribes to a stream for the lifecycle of the component, while ensuring that synchronous emits don't render twice. To use: export const Widget: SFC<{}> = () => {
const [channel, setChannel] = useState('friend-list')
const selectChannel = useCallback(({ target: { value } }) => setChannel(value), [])
const next = useStream((stream$) => stream$.pipe(
switchMap(() => interval(500).pipe(
startWith(-1),
scan<number, number[]>((data) => [...data, Math.floor(Math.random() * 10)], []),
take(4),
)),
), channel)
return el('div', null,
el('div', null,
el('select', { value: channel, onChange: selectChannel },
el('option', { value: 'friend-list' }, 'Friends'),
el('option', { value: 'enemy-list' }, 'Enemies'),
el('option', { value: 'grocery-list' }, 'Groceries'))),
el('h1', null, channel),
el('ul', null, ...(next || []).map((item, idx) => (
el('li', { key: idx }, item))))
)
} (accidentally fat finger closed this--just reopened) |
As a result of React's deprecation of the
componentWillMount
andcomponentWillReceiveProps
lifecycle hooks, recompose'smapPropsStream
now warnsI've been looking for an equivalent implementation using either Hooks, the new Suspense API, or new lifecycle methods, without much luck. The following works using the unsafe lifecycle methods
However, I haven't been able to accomplish the same thing without
UNSAFE_componentWillReceiveProps
. Given that renders are triggered by changes to theprops$
props stream, and not the props themselves, I suspect that the Suspense API could be helpful. Curious if anyone else is tackling the same issue.The text was updated successfully, but these errors were encountered: