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

Fix/remove finddomnode #308

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

ianchanning
Copy link

@ianchanning ianchanning commented Feb 22, 2023

An attempt to fix #239, but tries to go a step further than #255 as that fails with the children tests.

This is still not a perfect fix as I gave up and skipped one of the tests which I think is the least relevant:

 it("should handle children change", ...)

However it does handle all other tests.

I've also given up on handling Class Components for children - my main reference for doing this is the Material UI library. They continue to support class components - but warn that you will get the findDOMNode warning and suggest you use forwardRef or wrap your class component inside forwardRef.

https://mui.com/material-ui/guides/composition/#caveat-with-strictmode:

If you use class components for the cases described above you will still see warnings in React.StrictMode. ReactDOM.findDOMNode is used internally for backwards compatibility. You can use React.forwardRef and a designated prop in your class component to forward the ref to a DOM component. Doing so should not trigger any more warnings related to the deprecation of ReactDOM.findDOMNode.

 class Component extends React.Component {
   render() {
-    const { props } = this;
+    const { forwardedRef, ...props } = this.props;
     return <div {...props} ref={forwardedRef} />;
   }
 }

-export default Component;
+export default React.forwardRef((props, ref) => <Component {...props} forwardedRef={ref} />);

@@ -6,9 +6,9 @@ import InputMask from "../src";
function Input() {
const [value, setValue] = useState("");

function onChange(event) {
Copy link
Author

Choose a reason for hiding this comment

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

fix eslint error

} else {
module.exports = require("./lib/react-input-mask.development.js");
Copy link
Author

Choose a reason for hiding this comment

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

fix eslint errors

@@ -1088,7 +1093,7 @@ describe("react-input-mask", () => {
});

it("should allow to modify value with beforeMaskedStateChange", async () => {
function beforeMaskedStateChange({ nextState }) {
Copy link
Author

Choose a reason for hiding this comment

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

fix eslint error

@ianchanning
Copy link
Author

@@ -261,33 +265,35 @@ const InputMask = forwardRef(function InputMask(props, forwardedRef) {
setInputState(newInputState);
});

const refCallback = node => {
inputRef.current = node;
Copy link
Author

Choose a reason for hiding this comment

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

First main change is here - to remove findDOMNode - however that alone breaks the children usage.

return <ChildrenWrapper {...inputProps}>{children}</ChildrenWrapper>;
// {@link https://stackoverflow.com/q/63149840/327074}
const onlyChild = React.Children.only(children);
return React.cloneElement(onlyChild, { ...inputProps, ref: refCallback });
Copy link
Author

Choose a reason for hiding this comment

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

These lines were what was required to get the children working. As far as I can tell the main difference is that React.Children.only(children) returns the actual child which is then cloned where as React.cloneElement(children) which is what was being done in <ChildrenWrapper> returns a parent that you can't properly attach a ref to.

@@ -220,6 +221,9 @@ const InputMask = forwardRef(function InputMask(props, forwardedRef) {
}

const input = getInputElement();
if (!input) {
return;
}
Copy link
Author

Choose a reason for hiding this comment

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

minor fixed that helped with failing tests

@@ -144,6 +142,9 @@ const InputMask = forwardRef(function InputMask(props, forwardedRef) {
// https://github.com/sanniassin/react-input-mask/issues/108
function onMouseDown(event) {
const input = getInputElement();
if (!input) {
return;
}
Copy link
Author

Choose a reason for hiding this comment

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

minor fixed that helped with failing tests

}

return <input {...inputProps} />;
return <input ref={refCallback} {...inputProps} />;
Copy link
Author

Choose a reason for hiding this comment

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

I separate out the ref from the inputProps for clarity

return (
<div>
<input {...this.props} />
<input ref={innerRef} {...restProps} />
</div>
);
}
}
Copy link
Author

Choose a reason for hiding this comment

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

Doing a test with the new style of wrapping a class component in a React.forwardRef

function handleRef(ref) {
input = ref;
function handleRef(node) {
input = node;
Copy link
Author

Choose a reason for hiding this comment

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

Rename to match react docs. It is the node which is the equivalent to ref.current.

ref: ref => {
input = ref;
const refCallback = node => {
input = node;
Copy link
Author

@ianchanning ianchanning Feb 27, 2023

Choose a reason for hiding this comment

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

Rename ref ---> node to match react docs. It is the node which is the equivalent to ref.current.

@@ -146,10 +146,42 @@ function InvalidInput(props) {
}
```

**Caveat**: To support both class and function component children InputMask used to use `ReactDOM.findDOMNode`, which is now [deprecated](https://reactjs.org/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage). To handle removing this, direct child class components are **no longer supported**. The `children` component is now either:

1. a function component that implments `React.forwardRef`
Copy link

Choose a reason for hiding this comment

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

Suggested change
1. a function component that implments `React.forwardRef`
1. a function component that implements `React.forwardRef`

Copy link

@rokija rokija left a comment

Choose a reason for hiding this comment

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

wondering if this will be merged and published to npm?

I did try the other version from the author of this PR (#239 (comment))
And the issue seems to be fixed there.

@ianchanning
Copy link
Author

@rokija As far as I can tell this project is effectively archived. I created this PR so that anyone using the project can use this PR or my fork of it, but I am not expecting that this PR to be merged.

@ianchanning
Copy link
Author

I have put our fork of this as a stable version 3.0.0 now as we've been using it in production for 6 months https://github.com/mona-health/react-input-mask/

@johanguse
Copy link

I have put our fork of this as a stable version 3.0.0 now as we've been using it in production for 6 months https://github.com/mona-health/react-input-mask/

Thank you! But I can't use maskChar. On the @sanniassin I can.

Warning: React does not recognize the maskChar prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase maskchar instead. If you accidentally passed it from a parent component, remove it from the DOM element.

@johanguse
Copy link

Find out @ianchanning I can use maskPlaceholder thank you for forking!

@ianchanning
Copy link
Author

@johanguse As far as I know this is because maskChar in v2 was dropped in favour of maskPlaceholder in the v3-alpha code before I forked it. See #212

So indeed, maskPlaceholder is what you want :)

@coelhoreinaldo
Copy link

Thank you so much for your version of the lib! It is exactly what I need.

@theskillwithin
Copy link

plz merge 👍

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.

[@next] findDOMNode is deprecated in StrictMode
5 participants