jeffijoe / mobx-task

Makes async function state management in MobX fun.
MIT License
238 stars 6 forks source link

Hooks support #23

Closed jlil closed 4 years ago

jlil commented 4 years ago

It looks like all the task observables and helpers aren't working out of the box with the useObserver hook.

Example:

const MyComponent = () => {
    const {
        login
      } = useObserver(() => ({
        login: myStore.login
     }));

    useEffect(() => {
         login();
     }, [login]);

    return login.state // Always set to pending
    return login.match(...) // Always renders the pending match
    return login.result // always undefined
}

The only way to get it working is by using the following workaround:

const {
        login,
        loginState,
      } = useObserver(() => ({
        login: myStore.login
        loginState: myStore.login.state
     }));
jeffijoe commented 4 years ago

That's just how MobX's useObserver works. You have to access the props inside useObserver for MobX to rerender your component when those props change. You are meant to do something like this:

const MyComponent = () => {
    const {
        login
      } = myStore
    useEffect(() => {
         login();
     }, [login]);
    return useObserver(() => {
        // return your component from in here, all reactions are tracked
        return login.state
    })
}
jlil commented 4 years ago

@jeffijoe thanks for the quick reply.

In your example, how do you get the match to work without using login.state?

const MyComponent = () => {
    const {
        login
      } = myStore
    useEffect(() => {
         login();
     }, [login]);
    return useObserver(() => {
        // this doesn't react
        return login.match({
            pending: () => 'Pending',
            rejected: () => 'Error',
            resolved: () => 'Success',
          });
    })
}
jeffijoe commented 4 years ago

Are you using decorators or field initializers or just plain objects? Maybe try not destructuring, the task func shouldn’t change anyway unless you are doing something funky. I never had this issue.

jlil commented 4 years ago

@jeffijoe using decorators in the store, here's the full example:

// AuthStore.js

@task
login = async () => {
    return await AuthService.login();
};
// Login.js

const Login = () => {
    const {authStore} = useStores();
    useEffect(() => {
         authStore.login();
     }, [authStore.login]);

    return useObserver(() => {
        // this doesn't react
        return login.match({
            pending: () => 'Logging in',
            rejected: () => 'Error logging in',
            resolved: () => 'Logged in',
          });
    })
}
jeffijoe commented 4 years ago

I don't know if that actually works using a decorator AND a field initializer.

Try:

login = task(async () => { ... })
jlil commented 4 years ago

@jeffijoe no dice. I can spin up a codesandbox is it helps in debugging.

jeffijoe commented 4 years ago

Yes try that.

jeffijoe commented 4 years ago

Closing until a reproduction is available, I use Hooks myself and have no issues here.