demo1:一个正常的父子组件
const Son = () => {
console.log('son');
return <div>son</div>;
};
const Parent: React.FC = props => {
console.log('parent');
const [count, setCount] = useState<number>(0);
return (
<div>
<div onClick={() => setCount(prev => prev + 1)}>{count}</div>
<Son />
</div>
);
};
点击 count,输出 parent,还会输出 son。
Son 每次都跟随 Parent 重渲染完全没有必要,于是优化就开始了。
demo2:另一个正常的父子组件
const Son = () => {
console.log('son');
return <div>son</div>;
};
const Parent: React.FC = props => {
console.log('parent');
const [count, setCount] = useState<number>(0);
return (
<div>
<div onClick={() => setCount(prev => prev + 1)}>{count}</div>
{props.children}
</div>
);
};
const App = () => {
return (
<Parent>
<Son />
</Parent>
)
}
点击 count,只输出 parent,不输出 son。
也算是一种方法,但如果 Son 组件依赖于 Parent 的状态就不适用了。
demo3:React.memo() 用于优化性能
const Son = React.memo(() => {
console.log('son');
return <div>son</div>;
});
const Parent: React.FC = props => {
console.log('parent');
const [count, setCount] = useState<number>(0);
return (
<div>
<div onClick={() => setCount(prev => prev + 1)}>{count}</div>
<Son />
</div>
);
};
点击 count,只输出 parent,不输出 son。
效果类似于 pureComponent,也可以通过设置第二个参数实现 shouldComponentUpdate 的作用。
但是它只对比 props,而且有不生效的例外情况。
demo4:React.memo() 例外情况一
const Son: React.FC<{ normalFn: Function }> = React.memo(props => {
console.log('son');
return <div>son</div>;
});
const Parent: React.FC = props => {
console.log('parent');
const [count, setCount] = useState<number>(0);
const normalFn = () => {};
return (
<div>
<div onClick={() => setCount(prev => prev + 1)}>{count}</div>
<Son normalFn={normalFn} />
</div>
);
};
点击 count,输出 parent,还会输出 son。
父组件每次渲染,都会生成一个新的 normalFn 的实例,导致重复渲染。
demo5:useCallback 用于优化性能
const Son: React.FC<{ normalFn: Function }> = React.memo(props => {
console.log('son');
return <div>son</div>;
});
const Parent: React.FC = props => {
console.log('parent');
const [count, setCount] = useState<number>(0);
const normalFn = useCallback(() => {}, []);
return (
<div>
<div onClick={() => setCount(prev => prev + 1)}>{count}</div>
<Son normalFn={normalFn} />
</div>
);
};
点击 count,只输出 parent,不输出 son。
useCallback 用于缓存函数。
demo6:React.memo() 例外情况二
const Son: React.FC<{ normalFn: Function; normalValue: object }> = React.memo(props => {
console.log('son');
return <div>son</div>;
});
const Parent: React.FC = props => {
console.log('parent');
const [count, setCount] = useState<number>(0);
const normalValue = {
a: 'b',
};
const normalFn = useCallback(() => {}, []);
return (
<div>
<div onClick={() => setCount(prev => prev + 1)}>{count}</div>
<Son normalValue={normalValue} normalFn={normalFn} />
</div>
);
};
点击 count,输出 parent,还会输出 son。
同样的,父组件每次渲染,也会生成新的 normalValue 对象。
注意:这里如果 normalValue 不是引用类型的话就不会出现重渲染的问题。
demo7:useMemo 用于优化性能
const Son: React.FC<{ normalFn: Function; normalValue: object }> = React.memo(props => {
console.log('son');
return <div>son</div>;
});
const Parent: React.FC = props => {
console.log('parent');
const [count, setCount] = useState<number>(0);
const normalValue = useMemo(() => {
return {
a: 'b',
};
}, []);
const normalFn = useCallback(() => {}, []);
return (
<div>
<div onClick={() => setCount(prev => prev + 1)}>{count}</div>
<Son normalValue={normalValue} normalFn={normalFn} />
</div>
);
};
点击 count,只输出 parent,不输出 son。
useMemo() 用于缓存值。
demo8:对象尽量使用 useState 控制
const Son: React.FC<{ normalFn: Function; normalValue: object }> = React.memo(props => {
console.log('son');
return <div>son</div>;
});
const Parent: React.FC = props => {
console.log('parent');
const [count, setCount] = useState<number>(0);
const [normalValue, setNormalValue] = useState({
a: 'b',
});
const normalFn = useCallback(() => {}, []);
return (
<div>
<div onClick={() => setCount(prev => prev + 1)}>{count}</div>
<Son normalValue={normalValue} normalFn={normalFn} />
</div>
);
};
点击 count,只输出 parent,不输出 son。