函数组件
函数组件
函数组件实际上就是一个函数,接收props对象参数,返回一个React元素。
js
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
函数组件重新渲染
React
组件在组件的状态 state
或者组件的属性 props
改变的时候,会重新渲染。函数组件重新渲染时,会重新执行这个组件函数。
useCallback用法
js
let memoizedCallback = useCallback(fn, dependencies)
参数
fn:
想要缓存的函数。在初次调用(初次渲染)时,返回函数fn
。下一次调用(下一次渲染)时,如果依赖项没有变化,返回上次的函数fn
;如果依赖项发生了变化,返回最新的函数fn'
。
dependencies:
是否更新fn的依赖列表。响应式值包括 props
、state
,和所有在你组件内部直接声明的变量和函数。
返回值
在初次渲染时,useCallback
返回你已经传入的 fn
。
在之后的渲染中, 如果依赖没有改变,useCallback
返回上一次渲染中缓存的 fn
函数;否则返回这一次渲染传入的 fn
。
场景
减少子组件重新渲染
当父组件重新渲染时,子组件也会重新渲染,这样造成不必要的开销。React.memo
解决了这个问题。React.memo
会浅比较当前组件的props
与上一次渲染时的 props
。如果props
没有变化,跳过重新渲染。
当父组件的函数通过props
传递给子组件时,使用useCalback
包裹函数,配合React.memo
防止子组件重新渲染。
js
// 子组件使用 React.memo 优化
const ChildComponent = React.memo(function ChildComponent({ onClick }) {
console.log("ChildComponent rendered");
return <button onClick={onClick}>Click me</button>;
});
// 父组件使用 useCallback
function ParentComponent() {
const [count, setCount] = useState(0);
const [text, setText] = useState("");
// 使用 useCallback 记忆回调函数
const handleClick = useCallback(() => {
setCount(c => c + 1);
}, []); // 空依赖数组,因为不依赖任何值
return (
<div>
<input value={text} onChange={e => setText(e.target.value)} />
<p>Count: {count}</p>
<ChildComponent onClick={handleClick} />
</div>
);
}
防止频繁触发useEffect
如下代码,父组件的函数handleChange
函数传递给子组件。当在子组件中的useEffect hook
中调调用父组件handleChange
函数时,会导致无限循环渲染父子组件。
子组件useEffect
中调用handleChange
函数后,执行这个函数。函数中有语句setState
,触发父组件重新渲染。父组件重新渲染,在重新渲染时创建新的handleChange
函数。
handleChange
函数改变了,则又会执行useEffect
里面的handleChange
函数。这样造成了无限循环调用。
js
function Parent(){
const [state, setState] = useState()
function handleChange(input){
setState(...)
}
return <Child onChange={handleChange} />
}
function Child({onChange}){
const [state, setState] = useState()
useEffect(()=>{
onChange(...)
},[onChange])
return "Child"
}
下面使用useCallback
解决这一问题。给父组件的handleChange
函数使用useCallback
包裹。
js
function Parent(){
const [state, setState] = useState()
let handleChange = useCallback((input) => {
setState(...)
},[])
return <Child onChange={handleChange} />
}
function Child({onChange}){
const [state, setState] = useState()
useEffect(()=>{
onChange(...)
},[onChange])
return "Child"
}