I am trying to migrate my code to new react which supports react hooks. I am using useReducer, useState and useEffect. I could use the DidMount
and UnMount
in my code but do not have idea on how i implement DidUpdate
part as this one might create a re-rendering issue.
Here is how i have done
old code
class ImageBoard extends React.Component {
constructor() {
super();
this.state = {
canvas: undefined,
selected: undefined
};
}
handleDeleteKey(event) {
if (event.keyCode === 46 || event.keyCode === 8) {
event.preventDefault();
if (this.state.selected !== undefined) {
this.state.canvas.remove(this.state.selected);
this.setState({ selected: undefined });
}
}
}
componentDidMount() {
const canvas = new fabric.Canvas("canvas");
document.addEventListener("keydown",this.handleDeleteKey.bind(this),false);
canvas.on("object:selected", e => this.setState({ selected: e.target }));
canvas.on("selection:cleared", e => this.setState({ selected: undefined }));
this.setState({ canvas: canvas });
this.setCanvasBackground(this.props.getSelectedImage, canvas);
}
componentDidUpdate(prevProps) {
if (prevProps.getSelectedImage !== this.props.getSelectedImage) {
this.setCanvasBackground(this.props.getSelectedImage,this.state.canvas);
}
}
changed to following new code
const ImageBoard = () => {
let canvasEl = React.useRef(null);
const [selected, setSelected] = React.useState(null)
const [canvas, setCanvas] = React.useState(null)
const [state, _] = React.useReducer(imagesReducer, [])
const handleDeleteKey = event => {
if (event.keyCode === 46 || event.keyCode === 8) {
event.preventDefault();
if (selected !== undefined) {
canvas.remove(selected);
setSelected(undefined);
}
}
}
React.useEffect(() => {
const canvas = new fabric.Canvas("canvas");
document.addEventListener(
"keydown",
handleDeleteKey,
false
);
canvas.on("object:selected", e => setSelected(e.target));
canvas.on("selection:cleared", e => setSelected(undefined));
setCanvas(canvas);
setCanvasBackground(state.images.selectedImage, canvas);
return () => {
document.removeEventListener("keydown", handleDeleteKey, false);
}
}, [])
How do i write this following snippet in useEffect?
componentDidUpdate(prevProps) {
if (prevProps.getSelectedImage !== this.props.getSelectedImage) {
this.setCanvasBackground(this.props.getSelectedImage,this.state.canvas);
}
this.setCanvasBackground(this.props.getSelectedImage,this.state.canvas);
}
If the intention is to avoid unnecessary updates when same props are received and this applies to all props and not just getSelectedImage
, a component can be made pure:
const ImageBoard = memo(props => { ... });
So the component will be re-rendered only when new props are received, including useEffect
:
useEffect(() => {
// runs every time the component is rendered
setCanvasBackground(props.getSelectedImage, canvas);
})
If a part of a component should be evaluated only when new value of specific prop like getSelectedImage
is received, this is done with useMemo
or useEffect
hook, depending on the case. Since useEffect
can act as both componentDidUpdate
and componentDidMount
, this should be taken into account.
useEffect(() => {
// runs once on mount
const canvas = new fabric.Canvas("canvas");
document.addEventListener(
"keydown",
handleDeleteKey,
false
);
canvas.on("object:selected", e => setSelected(e.target));
canvas.on("selection:cleared", e => setSelected(undefined));
setCanvas(canvas);
// setCanvasBackground is moved to another hook
return () => {
document.removeEventListener("keydown", handleDeleteKey, false);
}
}, [])
useEffect(() => {
// runs every time new getSelectedImage is received, including initial render
setCanvasBackground(props.getSelectedImage, canvas);
}, [props.getSelectedImage])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With