useImperativeHandle
https://frontendmasters.com/courses/intermediate-react-v2/useimperativehandle/
useImperativeHandle
This is used very rarely, mostly for library authors.
It's used the reverse the data flow, so instead of moving from child to child, you go the other way. This let's a child control its parent.
The example below is for a form element.
//****useImperativeHandle.js****
import React, {
useState,
useRef,
useImperativeHandle,
forwardRef
} from "react";
// **** 1. we want to focus an input element. ↴
// which would be done by the parent
// **** 4. exposed by forwardRef. ↴
// if a component calls `ref` property
// it's going to make this function available
const ElaborateInput = forwardRef(
({ hasError, placeholder, value, update }, ref) => {
const inputRef = useRef();
// **** 2. exposing the function that the parent can run. ↴
useImperativeHandle(ref, () => {
return {
// **** 3. so the parent can "focus". ↴
// on the ElaborateInput
focus() {
inputRef.current.focus();
}
};
});
return (
<input
ref={inputRef}
value={value}
onChange={e => update(e.target.value)}
placeholder={placeholder}
style={{
padding: "5px 15px",
borderWidth: "3px",
borderStyle: "solid",
borderColor: hasError ? "crimson" : "#999",
borderRadius: "5px",
margin: "0 10px",
textAlign: "center"
}}
/>
);
}
);
const ImperativeHandleComponent = () => {
const [city, setCity] = useState("Seattle");
const [state, setState] = useState("WA");
const [error, setError] = useState("");
const cityEl = useRef();
const stateEl = useRef();
function validate() {
// lol I found it on StackOverflow : https://stackoverflow.com/a/25677072
if (
!/^([a-zA-Z\u0080-\u024F]+(?:. |-| |'))*[a-zA-Z\u0080-\u024F]+$/.test(
city
)
) {
setError("city");
// **** 5. here we can use the focus. ↴
cityEl.current.focus();
return;
}
if (!/^[A-Z]{2}$/.test(state)) {
setError("state");
stateEl.current.focus();
return;
}
setError("");
alert("valid form!");
}
return (
<div>
<h1>useImperativeHandle Example</h1>
<ElaborateInput
hasError={error === "city"}
placeholder={"City"}
value={city}
update={setCity}
ref={cityEl}
/>
<ElaborateInput
hasError={error === "state"}
placeholder={"State"}
value={state}
update={setState}
ref={stateEl}
/>
<button onClick={validate}>Validate Form</button>
</div>
);
};
export default ImperativeHandleComponent;
This technique is mostly reserved for library authors
You won't be writing much of these yourself.
We finished all the hooks!
This was the last hooks, now we've learned all the existing onces!