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

refactor: Simplify <Editor> with hooks #60

Merged
merged 3 commits into from
Jan 13, 2020
Merged

refactor: Simplify <Editor> with hooks #60

merged 3 commits into from
Jan 13, 2020

Conversation

edas
Copy link
Contributor

@edas edas commented Jan 8, 2020

Tentative de refactorisation de <Editor>

Objectif de limiter la complexité (je commençais à ne plus forcément voir toutes les interactions) et de permettre plus tard le test de la logique métier (qui me semblait plus que difficile à tester dans la forme monolithique)

@Crash--
Copy link
Contributor

Crash-- commented Jan 9, 2020

OMG j'ai pas encore relu, mais un grand OUI pour l'effort 👏

import useTitleChanges from 'hooks/useTitleChanges'
import useForceSync from 'hooks/useForceSync'
import useReturnUrl from 'hooks/useReturnUrl'
import useUser from 'hooks/useUser'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lot of hooks, I would be interested to know if they are really decoupled and usable in a standalone manner, each one from each one. At this point I am wondering if a class component would not be better than many decoupled hooks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of them are pretty specific to this component will probably never be used in another context.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean was : all this hooks have to be used in combination and it seems that we gain nothing with having them in different files since they are very coupled in functionality. Could there be only one hook useEditor or useNote doing all these things ?

Copy link
Contributor Author

@edas edas Jan 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have mixed feelings about that. My initial purpose was to explode all logic in different files in order to avoid a unique very long file.

The Editor does not do really more than this list of hooks. If we put everything in one unique hook, I'm afraid that we'll end un with exactly what we had before this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK.

My initial purpose was to explode all logic in different files in order to avoid a unique very long file.

I think the long file was not the problematic thing before, it was the super long render method.

If we put everything in one unique hook, I'm afraid that we'll end un with exactly what we had before this PR.

Extracting each hook and keeping them in the same file would have been OK for me. I personnally prefer when highly cohesive methods are in the same file, I find it easier to refactor and see the overall picture. However when things are not cohesive, sure, separate files are neded.

Here, Editor has to have knowledge of how to assemble all the little hooks, I have trouble saying why, but it troubles me that the orchestration of all those hooks is done in the render.

src/hooks/useForceSync.js Outdated Show resolved Hide resolved
Copy link
Contributor

@y-lohse y-lohse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to see this file split up :) A few comments on the individual hooks but the overarching split LGTM.

src/components/notes/editor-view.jsx Outdated Show resolved Hide resolved
src/hooks/useForceSync.js Show resolved Hide resolved
src/hooks/useNote.js Outdated Show resolved Hide resolved
setDocId(noteId)
}
},
[noteId, docId, setLoading, setTitle, setDoc, setDocId]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've never seen the setters as a dependency, is it useful? I would assumre they never change during the course of the hooks llfecycle, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the doc "The identity of the setCount function is guaranteed to be stable so it’s safe to omit".

So no, in this case (straight useState without wrapping or custom modification), it's not needed.

I see it as a good practice to always list all dependencies anyways. It won't trigger any problem and let us have a an habit that to not require us to check where the setter is from, nor forgive to add a setter in the list later if we change where it comes from.

https://stackoverflow.com/a/57180908

src/hooks/useNote.js Show resolved Hide resolved
)

if (docId == noteId) return { loading, title, doc, setTitle }
else return { loading: true, title: undefined, doc: undefined, setTitle }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't these values set though the first useEffect anyway?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope.

  • You run the useNote({noteId: 1}), load the note 1, fill title, doc and loading for docId=1.
  • Then you run useNote({noteId: 2}) in a future render. The effect is async and won't execute immediatly (it will be planned just after the render of the component calling useNote). You will then reach the end of useNote with noteId=2, docId=1, and the title/doc/loading values of docId=1, which is not what the calling component has asked.

Once you have an effect, you should always think that your data may lag of one render, and add safeguards to avoid filling obsolete values

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmh ok. I think the noteId/docId is a bit confusing and there might be a better wya to handle this, but it wasn't the scope of the PR and it's already easier to understand things with asingle hook, so LGTM 👍

src/hooks/useTitleChanges.js Outdated Show resolved Hide resolved
src/hooks/useTitleChanges.js Outdated Show resolved Hide resolved
src/components/notes/editor.jsx Show resolved Hide resolved
@edas edas mentioned this pull request Jan 9, 2020
@edas edas force-pushed the refactor/hooks branch 2 times, most recently from c3b8709 to aa8e76f Compare January 9, 2020 11:52
@edas edas marked this pull request as ready for review January 9, 2020 11:52
src/hooks/useNote.js Outdated Show resolved Hide resolved
src/hooks/useNote.js Outdated Show resolved Hide resolved
Copy link
Contributor

@Crash-- Crash-- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still find it diffult to understand the liaison between the hooks but it much way better now :)

src/lib/collab/stack-client.js Outdated Show resolved Hide resolved
function useServiceClient({ userId, userName, cozyClient }) {
return useMemo(
() => {
return new ServiceClient({ userId, userName, cozyClient })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find ServiceClient very generic, it's hard to know what are its responsibilities from here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok about that, but it should probably be a separate issue.

-> #64

})
},
[title, setTitle, serviceClient]
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two different strategies here to deal with a potentially false serviceClient, inside the function or outside, could this be refactored so that only 1 techniques is used ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the code be refactored so that the hooks do not have to deal with the presence of serviceClient ? It seems cumbersome and error prone.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried a few things, but with no success. I tried to first explode the logic to simplify Editor. We should be able to change the content of each hook in a future step

serviceClient.onTitleUpdated(noteId, modifiedTitle => {
if (title != modifiedTitle) {
setTitle(modifiedTitle)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hook adds an onTitleUpdated callback but does not deal with the cleanup of the callback, is it normal ? It is a bit surprising.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in serviceClient, we only have one callback per event, so each new onTitleUpdated replace the previous one.

Co-Authored-By: Quentin Valmori <[email protected]>
@edas edas mentioned this pull request Jan 9, 2020
@edas edas merged commit d76f34a into master Jan 13, 2020
@delete-merged-branch delete-merged-branch bot deleted the refactor/hooks branch January 13, 2020 09:36
cozy-bot pushed a commit that referenced this pull request Jan 13, 2020
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.

4 participants