-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Listeners cannot be immediately triggered upon addition #2435
Comments
Can't we expose a simple I am afraid that this change is gong to complicate too much the TS types and the internal implementation. |
Let's skip this for now. Can always revisit later. |
FWIW I'm actually about to use this util in Replay :) This seems to have value, and we ought to at least add it to the docs. Reopening the issue to remind myself of that. |
Related issue: #2698 . Lenz had a suggestion over there:
|
for what it's worth, i've come to the realisation that /**
* Attach a one-shot listener to the store, and resolves to `true` when `predicate` matches (or `false` if given `timeout` expires), then unsubscribes itself
* @param predicate Condition to match - receives action, state, and originalState (before action was dispatched)
* @param timeout Time in ms to wait before resolving promise to `false`.
* @returns Promise to wait on.
*/
export const listenForCondition = <State>(
predicate: AnyListenerPredicate<State>,
timeout?: number
): ThunkAction<Promise<boolean>, State, unknown, AnyAction> => (dispatch) =>
new Promise<boolean>((resolve) => {
let timeoutId: ReturnType<typeof setTimeout> | undefined;
const unsub = dispatch(
(addListener as TypedAddListener<State>)({
predicate,
effect: (action, { unsubscribe }) => {
unsubscribe();
resolve(true);
if (typeof timeoutId !== undefined) {
clearTimeout(timeoutId);
}
},
})
);
if (timeout) {
timeoutId = setTimeout(() => {
resolve(false);
unsub();
}, timeout);
}
}); |
Are you open to a PR that makes this clearer in the docs? I just spent a few hours down a rabbit hole wondering why nothing was working until I came to realise that |
@chmac yeah, docs PRs are always welcome! Out of curiosity, what were you trying to accomplish, and what did you want to have happen? What does your code look like? |
@markerikson I'm loading encrypted files from disk. First, I need to load the decryption key into redux. Then I have a startup routine that reads files, decrypts them, puts their contents into redux. So I have a bunch of startup processes which all need to "wait" for the key to become available. My code is something like: startAppListening({
actionCreator: startup,
effect: async (_, listenerApi) => {
await listenerApi.condition((_, state) => typeof state.keys.privateKey === 'string')
// do other stuff
}
}); My expectation was that I'll work up a little PR to add a small note to the docs. |
Listeners always run in response to a dispatched action, but this means there's no way to trigger one immediately. (Imagine a longer-running workflow, where we don't even care about what the triggering action might be, but just want to start running and doing other work as soon as the listener is defined.)
Perhaps we could add a
runImmediately: boolean
option to thestartListening
options? In that case you'd probably get either no action passed into the listener, or some kind of a dummy action.The alternative is to write your listener in such a way that you end up dispatching an action just to trigger it. Which is a valid thing to do, but also annoying.
Example of that from https://codesandbox.io/s/listen-for-condition-1b1b6g?file=/src/index.ts :
The text was updated successfully, but these errors were encountered: