Reputation: 753
I need to rewrite this old lifeCycle methods with useEffect hook and I am not sure how.
componentDidMount() {
document.addEventListener("mousedown", this.handleClickOutside);
this.setState({
defaultSelectText: this.props.defaultText
});
}
componentWillUnmount() {
document.removeEventListener("mousedown", this.handleClickOutside);
}
I have tried in this way but didn't really worked:
useEffect((props) => {
document.addEventListener("mousedown", this.handleClickOutside);
defaultSelectText(props.defaultText)
}, []);
Reproducible Example: https://codesandbox.io/s/weathered-sun-ej9tp?file=/src/DropDownSelect.js
Upvotes: 2
Views: 62
Reputation: 1074258
There are two parts to that:
You're right to use useEffect
, but useEffect
doesn't pass any argument to its callback. To remove the listener, you return a cleanup function:
useEffect(() => {
const handler = handleClickOutside;
document.addEventListener("mousedown", handler);
return () => {
document.removeEventListener("mousedown", handler);
};
}, []);
Notice that we capture the function we set in handler
so that we could be sure to remove the same function (in case handleClickOutside
gets recreated, as function sometimes do in function components).
Don't. :-) Props are state that your parent component manages. Your component shouldn't copy props to state, 99.9% of the time it's an anti-pattern; instead, it should just use the props. If the component needs to be able to change the value of a prop, the parent component should pass it a function to do that. See the documentation for the class
component getDerivedStateFromProps
function for more about not doing this.
In your case, you were only copying the prop to state on mount, which means that updates to the prop after mount were not being used. In the very rare use case where you need to do that, the equivalent with hooks is to use the prop as the initial value with useState
:
function Example({defaultText}) {
const [defaultSelectText, setDefaultSelectText] = useState(defaultText);
// ...
}
And for completeness, for the very rare use case where you need to have a state property that's updated whenever a prop is updated, you'd use useEffect
:
function Example({defaultText}) {
const [defaultSelectText, setDefaultSelectText] = useState(defaultText);
// ...
useEffect(() => {
setDefaultSelectText(defaultText);
}, [defaultText]); // <== Dependency is the prop
// ...
}
...but note that that particular example is pointless; the state value just mirrors the prop. You'd have to be doing something with the value when making it state for that to make sense.
Upvotes: 1
Reputation: 2475
Here is the code:
useEffect(() => {
const handler = handleClickOutside;
document.addEventListener("mousedown", handler); // Will be executed when component did mount
defaultSelectText(props.defaultText); // Will be executed when component did mount
return () => document.removeEventListener("mousedown", handler); // Will be executed when component will unmounted
}, []);
Happy coding :)
Upvotes: 1
Reputation: 670
You are almost there.
For componentDidMount
you pass empty array as dependencies which means, callback function passed to useEffect would be invoked only once i.e. after component is rendered/mounted the first time. For componentWillUnmount
, you return the function that you would like to be called as part of unmount operation.
useEffect((props) => {
document.addEventListener("mousedown", this.handleClickOutside);
defaultSelectText(props.defaultText);
return () => document.removeEventListener("mousedown", this.handleClickOutside);
}, []);
Upvotes: 1