1. 合理使用 useMemo 取代 useState + useEffect
不要把父组件传递进来的 props 直接赋值给子组件的 state ,然后又监听父组件的 props
// bad
function Son ({data}) {
const [fliterData, setFliterrData] = useState(data)
useEffect(() => {
setFliterrData(data => {...})
}, [data])
}
// good
const filterData = useMemo(() => {
return data.filter((item) => doSthing())
);
}, [data]);
2. 使用 useMemo 和 useCallback 优化性能
// bad
function Parent() {
const [count, setCount] = useState(0);
const handleIncrement = () => setCount(count + 1);
return <Son onClick={handleIncrement}>+</Son>
}
// good
function Parent() {
const [count, setCount] = useState(0);
const handleIncrement = useCallback(() => {
setCount(count + 1);
}, [count]);
return <Son onClick={handleIncrement}>+</Son>;
}
如果属性不需要传递给自定义子组件,可以不使用缓存
3. useEffect 别依赖一个对象变量,且变量有默认值,例如 {}、[]
// bad
function Parent({ data = {} }) {
// const data = {} 每次都会产生新对象
const handleIncrement = useCallback(() => {
dispatch(fetch('xxxxx')); // 这段代码可能会被一直执行,因为 data 的引用地址一直在变
}, [dispatch, data]);
return <Son onClick={handleIncrement}>+</Son>;
}
// good
function Parent({ data }) {
const handleIncrement = useCallback(() => {
dispatch(fetch('xxxxx'));
}, [dispatch, data]);
return <Son onClick={handleIncrement}>+</Son>;
}
4. useEffect 依赖过多
// bad
function Component({id, name}) {
useEffect(() => {
/* do something */
setId(id)
setName(name)
}, [id, name,...更多]) // 当依赖越多的时候,复杂度就越来越高
}
// good
function Component({id, name}) {
useEffect(() => {
/* do something */
setId(id)
}, [id])
useEffect(() => {
/* do something */
setName(name)
}, [name])
}
5. 万恶的 useCallback 的隐式嵌套
6. 带有业务逻辑的函数组件显示控制
带有业务逻辑的函数组件显示控制,例如弹框,他的显示隐藏最好由外部组件去控制,而不是在弹框组件内部去控制显示
// bad
function CustomModel({ visible }) {
if (!visible) return null;
return <Modal visible={visible}>我是弹框</Modal>;
}
// bad
function CustomModel({ visible }) {
useEffect(() => {
if(visible) {
// do something
}
}, [visible])
return <Modal visible={visible}>我是弹框</Modal>;
}
fun
// good
function Page() {
visible && <CustomModel visible />
}
7. hooks 耦合度太高
当函数式组件的功能越强大,它的复杂度会越来越高,尤其是函数式组件里面使用了 hooks,经常看到一个 Function Component,五百行甚至上千行的代码。 不要忘记拆分复杂度,就跟函数一样,调用其他函数,而不是把所有逻辑放到一个函数里。
如何让代码更优雅,有两条建议
- 函数逻辑的复用
- 函数逻辑的拆分
8. hooks 不是万能的
我们写 hooks 只是复用 js 逻辑,并不能复用 UI,当复用 UI 的时候,高阶组件和 render props 还是必须要用的
9.state 优先使用事件驱动,而不是依赖
- 事件驱动 state 变化,页面更新
- effect 里面去驱动 state,页面更新
最好先使用事件,再用 effect
10. 父组件调用子组件方法
forwardRef 结合 useImperativeHandle
//bad
const Son = forwardRef((props, ref) => {
const open = () => {
console.log('open');
};
const otherMethod = () => {
console.log('otherMethod');
};
});
function Parent() {
const ref = useRef();
useEffect(() => {
ref.current.open();
}, []);
return (
<>
<div>demo</div>
<Son ref={ref}></Son>
</>
);
}
// good
const Son = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
open() {
console.log('open');
},
}));
const otherMethod = () => {
console.log('otherMethod');
};
});
function Parent() {
const ref = useRef();
useEffect(() => {
ref.current.open();
}, []);
return (
<>
<div>demo</div>
<Son ref={ref}></Son>
</>
);
}