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

[EuiValidatableControl] Fixed ref not being handled properly when used with react-hook-form #4001

Merged
merged 7 commits into from
Sep 9, 2020

Conversation

crux153
Copy link
Contributor

@crux153 crux153 commented Sep 3, 2020

Summary

Related to react-hook-form/react-hook-form#2637.

This fixes react-hook-form's reset() method not working properly with EuiFieldText and more.

It seems like passing ref function with reference equality doesn't makes it to be called again on form reset, which is the behavior that react-hook-form lib depends on.

This can be fixed by simply moving the ref handling function from arrow function in class property to inlined arrow function. Although this creates a new function every render, its performance impact is negligible and facebook/react#8873 (comment) does this too.

Demo

https://codesandbox.io/s/zealous-grothendieck-k3923

Clicking the reset button only sets value on EuiCustomFieldText, not EuiFieldText.

Checklist

  • Check against all themes for compatibility in both light and dark modes
  • Checked in mobile
  • Checked in Chrome, Safari, Edge, and Firefox
  • Props have proper autodocs
  • Added documentation
  • Checked Code Sandbox works for the any docs examples
  • Added or updated jest tests
  • Checked for breaking changes and labeled appropriately
  • Checked for accessibility including keyboard-only and screenreader modes
  • A changelog entry exists and is marked appropriately

…d with react-hook-form

- Fix react-hook-form's reset() not working properly with EuiFieldText and more
- See react-hook-form/react-hook-form#2637
@kibanamachine
Copy link

Since this is a community submitted pull request, a Jenkins build has not been kicked off automatically. Can an Elastic organization member please verify the contents of this patch and then kick off a build manually?

Copy link
Contributor

@chandlerprall chandlerprall left a comment

Choose a reason for hiding this comment

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

Thanks for the simple test case & sandbox proving out your change. Had to do a little digging on react-hook-form to understand why the change is necessary: in the hook version every render pass resets the library's knowledge of the form and creates a new ref handler, which EuiValidatableControl was ignoring. This has been a lingering bug in this component for some time.

The proposed change introduces some overhead where a stable ref (e.g. a static function) will be called with null & then the element every render, which could be an issue if the ref function is doing heavy work. This is an edge case and resolving it correctly in EuiValidatableControl would be challenging at best, while consuming applications should be able to mitigate any potential issues without much effort.

The code changes look good to me. One request though: let's add a couple more cases to the control's ref management unit tests to ensure:

  • given two renders, where the child element changes (e.g. maybe EuiFieldText first and EuiFieldNumbere second)
    • with ref function, we expect to receive the child instance, null, and the new child instance
    • with a ref object (from e.g. useRef) we should see ref.current with the first child and then after a render see ref.current as the second child

- Utilize useMemo() to prevent stable ref from being called on every render
@crux153
Copy link
Contributor Author

crux153 commented Sep 4, 2020

@chandlerprall I've reimplemented EuiValidatableControl as function component, leveraging useMemo() hook to prevent stable ref from being called on every render.

https://codesandbox.io/s/white-haze-b5ucb

I'll add some tests soon.

@crux153
Copy link
Contributor Author

crux153 commented Sep 7, 2020

@chandlerprall I've added the requested unit tests and more. Please take a look!

@chandlerprall
Copy link
Contributor

jenkins test this

Copy link
Contributor

@chandlerprall chandlerprall left a comment

Choose a reason for hiding this comment

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

Awesome! The tests look great, as does the refactor to a function component. I've tested these changes locally and will merge when CI passes.

@crux153
Copy link
Contributor Author

crux153 commented Sep 9, 2020

@chandlerprall While reviewing the change, I found that useCallback makes much more sense than useMemo here. Sorry for interruption, but can you please check it again? I checked that it passes the tests properly (There should be no change in functionality.)

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4001/

@chandlerprall
Copy link
Contributor

useCallback looks good, re-running CI: jenkins test this

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4001/

@chandlerprall chandlerprall merged commit eee0b3b into elastic:master Sep 9, 2020
@chandlerprall
Copy link
Contributor

Merged. Thanks @crux153 for describing & re-creating the issue, as well as providing the fix!

@ince01
Copy link

ince01 commented Dec 30, 2020

image
How to fix this?

@crux153
Copy link
Contributor Author

crux153 commented Dec 30, 2020

@ince01 I guess you have two version of React running in your app. Checking your dependencies might help.

@ince01
Copy link

ince01 commented Dec 30, 2020

@crux153 I only found 1 version of React in node_modules, I use React v17 in this project. Can u suggest me some other solutions? This project is a mono-repo with 2 packages, 1 common UI library wrap @elastic/eui as a base dependency, 1 app consume this common UI library

@ince01
Copy link

ince01 commented Dec 31, 2020

image
@crux153 I use yarn 2 workspaces for the package manager, and this is the result when I check to React in dependencies tree.

@crux153
Copy link
Contributor Author

crux153 commented Dec 31, 2020

@ince01 Hmm... this is weird, as I don't see any reason of this breaking rules of hooks. If you are passing ref to child of EuiValidatableControl, can you share it? If you're not passing ref, then I think this shouldn't be problem related to this PR.

@ince01
Copy link

ince01 commented Dec 31, 2020

@crux153 I don't use ref, this is git repo of the project. You can check it. Follow these steps to start this project. I'm looking forward to ur help :((

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