const ComA = (props) => { const { num = 1, config } = props; return <>{num}</>; }; // 堆代码 duidaima.com // or const ComA = ( { num = 1, config }) => { return <>{num}</>; }; // use const App = () => { return <ComA />; }
大多数 Props 解构可能就是这样,确实很方便也很优雅,对于具有默认值的 Props 这是一种常见的做法。
const ComA = (props) => { const { num = 1, config = { a: 1 } } = props; return <>{num}</>; };还是很优雅,然后继续迭代,某个需求的 useEffect 突然要依赖 config.a,由于 config 只有一个属性,所以代码补全的时候直接帮你补上了 config,如下
const ComA = (props) => { const { num = 1, config = { a: 1 } } = props; useEffect(() => { console.log("config.a", config.a); }, [config]); return <>{num}</>; };
但是随后问题袭来。
// 堆代码 duidaima.com // App 开始控制 ComA num props 的值 export default function App() { const [num, setNum] = useState(0); return ( <div className="App"> <button onClick={() => setNum((prev) => prev + 1)}>setNum</button> <br /> <ComA num={num} /> </div> ); }
config = { type: { key: '', value: '' } }
但是究其原因都是对象重新创建的问题。
// config = { a: 1 } -> config = DEFAULT_CONFIG const DEFAULT_CONFIG = { a: 1 }; const ComA = (props) => { const { num = 1, config = DEFAULT_CONFIG } = props; useEffect(() => { console.log("config.a", config.a); }, [ob]); return <>{num}</>; };
import { useState, useEffect } from "react"; const DEFAULT_CONFIG = { a: 1 }; const ComA = (props) => { const { num = 1, config = DEFAULT_CONFIG } = props; useEffect(() => { console.log("config.a", config.a); }, [config]); return ( <> <button onClick={() => { config.a = 0; }} > !!set config.a!! </button> <br /> {num} </> ); }; export default function App() { const [num, setNum] = useState(0); const [config, setConfig] = useState(); return ( <div className="App"> <button onClick={() => setNum((prev) => prev + 1)}>setNum</button> <button onClick={() => setConfig({ a: 2 })}>initConfig</button> <button onClick={() => setConfig(undefined)}>resetConfig</button> <br /> <ComA num={num} config={config} /> </div> ); }在上面的代码中:
const DEFAULT_CONFIG = { a: 1 }; const ComA = (props) => { const { num = 1 } = props; const config = useMemo(() => { return props.config ? props.config : { ...DEFAULT_CONFIG }; }, [props.config]); useEffect(() => { console.log("config.a", config.a); }, [config]); ... }
组件内部修改 Props 的值是不被建议,不符合规范的做法,但是谁能决定写 React 的人写代码的姿势呢?
import { useState, useEffect, useRef } from "react"; // 堆代码 duidaima.com // before // useEffect(() => { // console.log("num", num, "config.a", config.a); // }, [num, config]); const ComA = (props) => { const { num = 1, config = { a: 1 } } = props; const configRef = useRef(); configRef.current = config.a; useEffect(() => { const config = configRef.current; console.log("num", num, "config.a", config.a); }, [num]); return <>{num}</>; }; export default function App() { const [num, setNum] = useState(0); return ( <div className="App"> <button onClick={() => setNum((prev) => prev + 1)}>setNum</button> <br /> <ComA num={num} /> </div> ); }这个案例里的 useEffect 监听了 num 而不是 config,在 num 变化时再通过 useRef 拿到最新的 config,而不去关心 config 的值是不是最新的,避免 config 因为解构重复更新。
这个解决方案没有解决 config 值重复变化的问题,问题依然存在!