管理相对复杂的状态数据
定义一个reducer函数,根据action值的不同返回不同的状态
在组件中调用useReducer并传入reducer函数和状态的初始值
事件发生时,通过dispatch函数分派一个对象,即通知reducer具体返回哪个状态对应的操作
import { useReducer } from "react";
function reducer(state, action){
switch(action.type){
case 'INC':
return state + 1
case 'DEC':
return state - 1
case 'SET':
return action.payload
default:
return state
}
}
function App() {
const [state, dispatch] = useReducer(reducer, 0)
return (
{state}
{/* 自定义参数 */}
);
}
export default App;
组件重新渲染时缓存计算的结果
应用场景:消耗比较大的计算
import { useMemo, useState } from "react"
function fib(num){
console.log('计算函数执行了')
if ( num < 3 )return 1
return fib(num - 1) + fib(num - 2)
}
function App() {
const [count1, setCount1] = useState(0)
const [count2, setCount2] = useState(0)
// 如果执行下面注释的代码 即使只有count2变化 计算函数也会执行
// const result = fib(count1)
const result = useMemo(() => {
return fib(count1)
},[count1])
console.log('组件重新渲染')
return (
{result}
);
}
export default App;
react组件默认的渲染机制:只要父组件重新渲染子组件就会重新渲染
const MemoComponent = memo(function SomeComponent(props){
// ...
})
只有props发生变化时,memo包裹的缓存组件才会重新渲染
import { useState, memo } from "react";
const MemoSon = memo(function Son(props){
console.log('子组件渲染了')
return Son
})
function App() {
const [count, setCount] = useState(0)
console.log('父组件渲染了')
return (
);
}
export default App;
使用memo缓存组件之后,react会对每一个prop使用Object.is比较新值和老值,返回true表示没有变化
1. 传递一个简单类型的prop prop变化时组件重新渲染
2. 传递一个引用类型的prop 比较的是新值和旧值的引用是否相等 当父组件的函数重新执行时 实际上形成的是新的数组引用
3. 保证引用稳定 -> useMemo 组件渲染的过程中缓存一个值
//情况1 传递简单数据
//点击按钮 子组件会发生变化
import { useState, memo } from "react";
const MemoSon = memo(function Son(props){
console.log('子组件渲染了')
return Son{props.count}
})
function App() {
const [count, setCount] = useState(0)
console.log('父组件渲染了')
return (
);
}
export default App;
//情况2 传递引用数据
//点击按钮 子组件会发生变化
import { useState, memo } from "react";
const MemoSon = memo(function Son(props){
console.log('子组件渲染了')
return Son{props.list}
})
function App() {
const [count, setCount] = useState(0)
console.log('父组件渲染了')
const list = [1,2,3]
return (
);
}
export default App;
//情况3 使用useMemo进行缓存
//子组件不再重新渲染
import { useState, memo, useMemo } from "react";
const MemoSon = memo(function Son(props){
console.log('子组件渲染了')
return Son{props.list}
})
function App() {
const [count, setCount] = useState(0)
console.log('父组件渲染了')
const list = useMemo(()=>{
return [1,2,3]
}, [])
return (
);
}
export default App;
4. 给子组件传递函数
React.memo检测的是props中数据的栈地址是否改变。而父组件重新构建的时候,会重新构建父组件中的所有函数(旧函数销毁,新函数创建,等于更新了函数地址),新的函数地址传入到子组件中被props检测到栈地址更新。也就引发了子组件的重新渲染。
在组件多次渲染的时候缓存函数
使用场景:在往子组件传入了一个函数并且子组件被React.momo缓存了的时候使用
//情况4 传入函数
//点击按钮子组件不会重新渲染 因为使用useCallback缓存
import { useState, memo, useMemo, useCallback } from "react";
const Input = memo(function Input({onChange}){
console.log('子组件重新渲染')
return onChange(e.target.value)} />
})
function App() {
const [count, setCount] = useState(0)
const changeHandler = useCallback((value)=> console.log(value), [])
return (
);
}
export default App;
import { useRef,forwardRef } from "react";
//如果用下面的函数 sonRef的值是null
// function Son(){
// return
// }
const Son = forwardRef((props, ref)=> {
return
})
function App() {
const sonRef = useRef(null)
const showRef = ()=>{
console.log(sonRef)
}
return (
);
}
export default App;