Skip to content
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

Rewrite: useReducer based implementation #33

Merged
merged 1 commit into from
Nov 8, 2019

Conversation

dai-shi
Copy link
Owner

@dai-shi dai-shi commented Nov 5, 2019

https://twitter.com/dai_shi/status/1185849112895225856

In react-hooks-async, I tried useReducer but it was too ugly, the current code with forceUpdate is pretty readable. So, I gave up. I could try further. There could be a better implementation with only immutable states. I wish somebody would try.

https://twitter.com/dai_shi/status/1191518644389335040

  1. react-hooks-async implementation is not very declarative.

I actually agree. Used to useReducer, but changed assuming mutations are easier to read. I'll try again. It should be technically possible

So, it should be technically possible to code without forceUpdate.
It would be better because forceUpdate is not a good pattern unless there's an avoidable reason.

Now, I hope it's not too ugly now. I don't preserve the exact same behavior(no abort in this hook), but the public API should be able to be used the same as before.

There might be room for improvements. a) dispatchRef doesn't seem nice, b) do we really need two symbols? c) Is the use of useLayoutEffect correct?

I found implementing this is pretty tricky, and I'm not sure how readable it it.

@dai-shi
Copy link
Owner Author

dai-shi commented Nov 5, 2019

@dagda1 You wanna have a look?

@dagda1
Copy link

dagda1 commented Nov 5, 2019

HI @dai-shi,

I feel really awful. I was not meaning to criticise. I was just saying that somebody in the comments reminded me of react's declarative nature. I learned a lot looking at this library and I think it is excellent.

I will have a look at the PR

@dai-shi
Copy link
Owner Author

dai-shi commented Nov 5, 2019

I was not meaning to criticise.

@dagda1 Please don't get it wrong. I never felt this as criticism. It's a suggestive feedback. I mean I thought the use of forceUpdate wasn't nice. It should be a last resort. I had wanted to rewrite this.

My implementation was originally useReducer based, but when I supported the "callback" pattern, I changed it to forceUpdate+memoization. Now, I got to know useReducer better, I'm using lazy initialization this time.

@dagda1
Copy link

dagda1 commented Nov 5, 2019

I think this is much better but the one thing I don't see is a state change for an Error.

I like the reducer in the codesandbox I referenced in the article.

@dai-shi
Copy link
Owner Author

dai-shi commented Nov 5, 2019

      let result = null;  
      let error = null;  
      try {  
        result = await func(abortController, ...args);  
        dispatchRef.current({                                                 
          type: 'RESULT',                                                     
          taskId,  
          runId,   
          result,  
        });  
      } catch (e) {  
        if (e.name !== 'AbortError') {  
          error = e;  
        }  
        dispatchRef.current({  
          type: 'ERROR',                                                      
          taskId,                                                             
          runId,                
          error,  
        });  
      }  
      if (error) throw error;  
      return result;  

You mean you prefer this?

@dagda1
Copy link

dagda1 commented Nov 5, 2019 via email

@dai-shi
Copy link
Owner Author

dai-shi commented Nov 5, 2019

@dagda1

yes,an error is a state change IMO

But, it was already a state change. I think it's just coding style preference.

@dagda1
Copy link

dagda1 commented Nov 6, 2019

should abort be a state changed also?

@dai-shi
Copy link
Owner Author

dai-shi commented Nov 6, 2019

Hm, currently, we have no aborting nor aborted state, because abort() is usually called on unmount or on starting a new task and no component read the state. If we had a use case to use aborting state, we would consider that. How does that sound?

@dagda1
Copy link

dagda1 commented Nov 6, 2019

i did have a use case recently but it was for uploading large files into azure in chunks. are you saying abort is only called on unmount

@dai-shi
Copy link
Owner Author

dai-shi commented Nov 6, 2019

No, I only meant "usually". Let's open a new issue about it. I think it's a good use case to dig in.

@dai-shi
Copy link
Owner Author

dai-shi commented Nov 8, 2019

Let me merge this.

@dagda1 Would you open a new issue for aborting state with a use case?

@dai-shi dai-shi merged commit 46e1962 into master Nov 8, 2019
@dai-shi dai-shi deleted the use-reducer-based-implementation branch November 8, 2019 23:52
@dai-shi
Copy link
Owner Author

dai-shi commented Nov 25, 2019

should abort be a state changed also?

Actually, I ran into an issue because of no aborted state. There is a bug in the current typings after #30.

@alvinthen
Copy link

Hey, FYI, useLayoutEffect is all fine except that it gives all bunch of warnings in SSR

@dai-shi
Copy link
Owner Author

dai-shi commented Nov 28, 2019

@alvinthen You are right. That's a really undesired behavior of React.
Fair enough. Let's see how useIsomorphicLayoutEffect hack works.

@dai-shi dai-shi mentioned this pull request Nov 28, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants