几个规则:
- 单纯子组件渲染(子组件内state变化)不会引起父组件渲染。
- 当父组件重渲染的时候,会默认递归的重渲染所有子组件(不做shouldUpdate等优化的前提下)。
- 子组件渲染可能会引起父组件渲染。(比如父组件中获取redux的数据传给子组件,而子组件中又修改了redux数据。即子组件修改redux=>触发父组件props变化=>触发子组件props变化)
优化
useMemo和useCallback
useMemo和useCallback都会在组件第一次渲染的时候执行,之后会在其依赖的变量发生改变时再次执行;并且这两个hooks都返回缓存的值,useMemo返回缓存的变量 ,useCallback返回缓存的函数。和useEffect不同的是,前两者不能处理副作用。
useMemo
const Example = (props) => {
// 产品名称、价格
const [price, setPrice] = useState('')
const [name, setName] = useState('init')
// 假设有一个业务函数 获取产品的名字
const getProductName = () => {
console.log('getProductName触发')
return name
}
return (
<div>
<h1>name:{
getProductName()}</h1>
<h1>price:{
price}</h1>
name:<input onChange={
(evt) => setName(evt.target.value)}></input>
<br />
price:<input onChange={
(evt) => setPrice(evt.target.value)}></input>
</div>
)
}
在这个例子中,用户可以输入商品的名称和价格并展示。但我们会发现,即使只输入了price,由于render函数的触发,getProductName也会重新执行,但这是没有意义的,因为name并没有改变。
用useMemo重写
const Example = (props) => {
// 产品名称、价格
const [price, setPrice] = useState('')
const [name, setName] = useState('init')
// 假设有一个业务函数 获取产品的名字
const getProductName = useMemo(() => {
console.log('getProductName触发')
return name
},[name]) //这里如果不加上对name的依赖 就只会缓存初始的值,永远返回 'init'
return (
<div>
<h1>name:{
getProductName}</h1>
<h1>price:{
price}</h1>
name:<input onChange={
(evt) => setName(evt.target.value)}></input>
<br />
price:<input onChange={
(evt) => setPrice(evt.target.value)}></input>