jeffijoe / mobx-task

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

No unstarted state? #5

Closed jmeyers91 closed 6 years ago

jmeyers91 commented 6 years ago

Why isn't there an unstarted state? I'd like to be able to determine whether or not the task has started.

My use-case: I'd like to show a login request loading spinner when a task is pending, but because the task is pending before it is called, the loading spinner shows immediately.

jeffijoe commented 6 years ago

Use @task.resolved, then the task starts in a resolved state. I use this for the use case you just described. 😀

jeffijoe commented 6 years ago

@jmeyers91 here's an example: https://github.com/jeffijoe/mobx-task/issues/4#issuecomment-343651629

const loadMore = task.resolved(async () => {
  // ...
})

const View = () => (
  <div>
    {loadMore.pending
      ? <Spinner />
      : <button onClick={loadMore}>Load More</button>
    }
  </div>
)
jeffijoe commented 6 years ago

Closing due to inactivity. 😄

fend25 commented 4 years ago

Hello. @jeffijoe, sorry for commenting outdated issue, but it's still better than start a duplicate.

So, unfortunately task.resolved is a partial workaround, not a solution.

For example, I request some array from server. The field in the store before invoking task is empty array. The application has no way to understand, whether the server has responded with empty array result or the request was not requested still.

I wanted to fork your project and add some aside flag, which doesn't change state, but the code is a bit complicated and I'm afraid that I can brake something. So couldn't you please provide flag which indicates whether the task somewhen been called.

jeffijoe commented 4 years ago

@fend25 for that use case, you can do

const hasBeenCalled = fn.result !== undefined
fend25 commented 4 years ago

@jeffijoe Thank you for such fast response. Sorry, I didn't get your point.

What is fn?

store:

@observable arr = []

@task
getArrTask = async () => {
  this.arr = await api.getArray()
};

use:

console.log(store.getArrTask.resolved) // false
console.log(store.getArrTask.result) // undefined
store.getArrTask()

// and later
console.log(store.getArrTask.resolved) // true
console.log(store.getArrTask.result) // undefined
jeffijoe commented 4 years ago

fn is your task function. Fixed your example:

store:

@observable arr = []

@task
getArrTask = async () => {
  this.arr = await api.getArray()
  return this.arr
};

use:

console.log(store.getArrTask.resolved) // false
console.log(store.getArrTask.result) // undefined
await store.getArrTask()

// and later
console.log(store.getArrTask.resolved) // true
console.log(store.getArrTask.result) // [.....]
fend25 commented 4 years ago

@jeffijoe Thank you. Yes, it works.

But it looks like a workaround, which causes more useless code, which some analyzer (maybe programmer) can reduce and brake the business logic.

jeffijoe commented 4 years ago

If I were to add a flag, I don't know what to call it. started is ambiguous with pending.

fend25 commented 4 years ago

@jeffijoe

{!task.called && <Button onClick={task}/>}
{!task.pending && <Loader/>}

When never called, show button, When pending, resolved, rejected, any other than !called, dont show button

Now, we cant differ pre-pending from real pending state. At least without hack with returning some result from task and checking it. And even so, it makes code non-consistent: isCalled(task) when all another states are checked via task.desiredState

As example of it is useful, I can provide an example of same functionality lib from Vue world:

And thank you very much. Except this, the lib is brilliant.

fend25 commented 4 years ago

@jeffijoe

Are you ok? I worry.

fend25 commented 4 years ago

BTW, I was thinking about Promise. It has three states because the fourth one - not initiated is could be easy reached from the code logic. The code is determined and it is imperative and we always know where we are in the code now - before or after invocation of Promise. So we dont need to get it from promise - we already know whether it was invoked or no.

The JSX markup is declarative - we just declare the state transform we want to be done. We don't know when the transform will be invoked and we don't know which state will be passed - we just have to describe the transformation for all possible cases. And in that way we get the fourth task state - not initiated. I remembered that I had made a picture for a conference a couple years ago:

request_state_diagram

fend25 commented 4 years ago

I appreciate your work very much and I don't persuade you to redo your work or change something is existent API. Just to add a little aside flag to be able to check whether the function was somewhen invoked.

jeffijoe commented 4 years ago

Sorry I just haven't had the time to do this.