React useEffect 依赖项或 useCallback 似乎会导致重新渲染
React useEffect dependency or useCallback seem to cause re-renders
我有一个 useEffect 函数,可以拍摄图像、调整图像大小以供显示并准备好上传。虽然这有效,但我收到 React 警告以在 useEffect 依赖项列表中列出该函数。但是,当我这样做时,即使将函数移至 useCallback,它也会导致连续重新呈现。代码如下...
import React, { useEffect, useRef, useCallback } from 'react'
const Canvas = (props) => {
const { width = 180, height = 220, img, onChange = null, setFile = null} = props
const canvas = useRef(null)
const setBlobFile = useCallback(
(blob) => {
setFile(blob)
},
[setFile]
)
useEffect(() => {
if (img) {
console.log("Canvas useEffect ...", img)
var image = new Image()
image.src = img
image.onload = () => {
canvas.current.getContext("2d")
canvas.current.getContext("2d").clearRect(0, 0, width, height);
canvas.current.getContext("2d").drawImage(image, 0, 0, image.width, image.height, 0, 0, width, height)
canvas.current.toBlob((blob) => {
setBlobFile(blob)
})
}
}
}, [img, width, height, setBlobFile])
const onFileSelect = (e) => {
const objectURL = URL.createObjectURL(e.target.files[0])
onChange(objectURL)
}
return (
<div onClick={onClick}>
<label htmlFor='upload'>
<canvas ref={canvas} width={width} height={height} />
<input type='file' id='upload' onChange={(e) => onFileSelect(e)} style={{ display: 'none' }} />
</label>
</div>
)
}
export { Canvas as default }
父组件提供setFile例程来设置上传文件
...
const [selectedFile, setSelectedFile] = useState(new File([""], ""))
const setFile = (aBlob) => {
var img = new Image()
img = aBlob
setSelectedFile(new File([aBlob], "image.png", {
type: 'image/png',
}))
}
...
知道为什么我会看到这种行为吗?我认为 useCallback() 方法应该停止重新渲染,但它似乎创建了它们。我怎样才能避免警告并停止重新渲染行为?感谢您的观看。
你必须在创建函数的地方使用useCallback
,而不是在使用它的地方。
const setBlobFile = useCallback(
(blob) => {
setFile(blob)
},
[setFile]
)
in Canvas
在 setFile
更改时无法防止重新渲染,因为 setBlobFile
在 setFile
更改时仍会更改,因为 setFile
作为依赖。
相反,您需要在首先创建 setFile
的父组件中使用 useCallback
:
const [selectedFile, setSelectedFile] = useState(new File([""], ""))
const setFile = useCallback((aBlob) => {
var img = new Image()
img = aBlob
setSelectedFile(new File([aBlob], "image.png", {
type: 'image/png',
}))
}, [setSelectedFile]);
这将按预期工作,因为 useState
保证 setter 函数 (setSelectedFile
) 永远不会在渲染之间改变,因此 setFile
永远不会在渲染之间改变.
我有一个 useEffect 函数,可以拍摄图像、调整图像大小以供显示并准备好上传。虽然这有效,但我收到 React 警告以在 useEffect 依赖项列表中列出该函数。但是,当我这样做时,即使将函数移至 useCallback,它也会导致连续重新呈现。代码如下...
import React, { useEffect, useRef, useCallback } from 'react'
const Canvas = (props) => {
const { width = 180, height = 220, img, onChange = null, setFile = null} = props
const canvas = useRef(null)
const setBlobFile = useCallback(
(blob) => {
setFile(blob)
},
[setFile]
)
useEffect(() => {
if (img) {
console.log("Canvas useEffect ...", img)
var image = new Image()
image.src = img
image.onload = () => {
canvas.current.getContext("2d")
canvas.current.getContext("2d").clearRect(0, 0, width, height);
canvas.current.getContext("2d").drawImage(image, 0, 0, image.width, image.height, 0, 0, width, height)
canvas.current.toBlob((blob) => {
setBlobFile(blob)
})
}
}
}, [img, width, height, setBlobFile])
const onFileSelect = (e) => {
const objectURL = URL.createObjectURL(e.target.files[0])
onChange(objectURL)
}
return (
<div onClick={onClick}>
<label htmlFor='upload'>
<canvas ref={canvas} width={width} height={height} />
<input type='file' id='upload' onChange={(e) => onFileSelect(e)} style={{ display: 'none' }} />
</label>
</div>
)
}
export { Canvas as default }
父组件提供setFile例程来设置上传文件
...
const [selectedFile, setSelectedFile] = useState(new File([""], ""))
const setFile = (aBlob) => {
var img = new Image()
img = aBlob
setSelectedFile(new File([aBlob], "image.png", {
type: 'image/png',
}))
}
...
知道为什么我会看到这种行为吗?我认为 useCallback() 方法应该停止重新渲染,但它似乎创建了它们。我怎样才能避免警告并停止重新渲染行为?感谢您的观看。
你必须在创建函数的地方使用useCallback
,而不是在使用它的地方。
const setBlobFile = useCallback(
(blob) => {
setFile(blob)
},
[setFile]
)
in Canvas
在 setFile
更改时无法防止重新渲染,因为 setBlobFile
在 setFile
更改时仍会更改,因为 setFile
作为依赖。
相反,您需要在首先创建 setFile
的父组件中使用 useCallback
:
const [selectedFile, setSelectedFile] = useState(new File([""], ""))
const setFile = useCallback((aBlob) => {
var img = new Image()
img = aBlob
setSelectedFile(new File([aBlob], "image.png", {
type: 'image/png',
}))
}, [setSelectedFile]);
这将按预期工作,因为 useState
保证 setter 函数 (setSelectedFile
) 永远不会在渲染之间改变,因此 setFile
永远不会在渲染之间改变.