不写性能优化的时候
const Child = (props) => {
console.log(child function is recalled)// count1改变时多次执行
return (
<div>
<h1>{ props.count2}</h1>
</div>
)
}
function app () {
const [count1.setCount1] = useState(0)
const [count2.setCount2] = useState(0)
return (
<div>
<h1>count1:{count1}</h1>
<button onClick={()=> setCount1(count1+1)}>+</button>
<Child count2={count2}/>
<button onClick={()=> setCount2(count2+1)}>+</button>
</div>
)
}
root.render(<App />)
memo
const Child = memo((props) => {
console.log(child function is recalled)// count1改变时不会多次执行
return (
<div>
<h1>{ props.count2}</h1>
</div>
)
})
/**
*
* 函数组件最大的弱点:渲染执行
* 当一个组建的状态发生了改变的时候 相关视图是必然要更新的
* 函数组件在视图更新的需求来临的时候 函数是必然要执行的
*/
function app () {
const [count1.setCount1] = useState(0)
const [count2.setCount2] = useState(0)
return (
<div>
<h1>count1:{count1}</h1>
<button onClick={()=> setCount1(count1+1)}>+</button>
<Child count2={count2}/>
<button onClick={()=> setCount2(count2+1)}>+</button>
</div>
)
}
root.render(<App />)
useMemo
/**
* memo会对引用进行比较,这种比较时浅比较,
* 如果更新了一个新的引用,那么child就会被执行
* count1更新 app重新执行 child 必然要重新赋值一个新引用
*/
const Child = memo((props) => {
console.log(child function is recalled)// count1改变时会多次执行
return (
<div>
<h1>{ props.childData.count2}</h1>
</div>
)
})
function app () {
const [count1.setCount1] = useState(0)
const [count2.setCount2] = useState(0)
const childData = {
count2
}
return (
<div>
<h1>count1:{count1}</h1>
<button onClick={()=> setCount1(count1+1)}>+</button>
<Child childData={childData}/>
<button onClick={()=> setCount2(count2+1)}>+</button>
</div>
)
}
const Child = memo(props) => {
console.log(child function is recalled)// count1改变时不会多次执行
return (
<div>
<h1>{ props.childData.count2}</h1>
</div>
)
}
function app () {
const [count1.setCount1] = useState(0)
const [count2.setCount2] = useState(0)
// const childData = {
// count2
// }
// 只有依赖变了才会返回新的引用
// 不是为了子组件/返回常量的时候,不需要使用useMemo
const childData = useMemo(() => ({count2}),[count2])
/**
* const newCount1 = useMemo(()=>count1*2,[count1])
* 类似vue计算属性 可以使用useMemo
*/
return (
<div>
<h1>count1:{count1}</h1>
<button onClick={()=> setCount1(count1+1)}>+</button>
<Child childData={childData}/>
<button onClick={()=> setCount2(count2+1)}>+</button>
</div>
)
}
useCallback
const Child = memo(props) => {
console.log(child function is recalled)// count1改变时会多次执行
return (
<div>
<h1>{props.childData.count2}</h1>
<button onClick={props.setCount2}>+</button>
</div>
)
}
function app () {
const [count1.setCount1] = useState(0)
const [count2.setCount2] = useState(0)
const cbSetCount2 = () => {
() => setCount2(count2 + 1);
}
return (
<div>
<h1>count1:{count1}</h1>
<button onClick={()=> setCount1(count1+1)}>+</button>
<Child childData={childData} setCount2={cbSetCount2 } />
</div>
)
}
const Child = memo(props) => {
console.log(child function is recalled)// count1改变时不会多次执行
return (
<div>
<h1>{props.childData.count2}</h1>
<button onClick={props.setCount2}>+</button>
</div>
)
}
function app () {
const [count1.setCount1] = useState(0)
const [count2.setCount2] = useState(0)
// 函数是静态的 一般情况下是不会增加依赖的 除非是用户配置 比如面向对象 在this上增加函数 prototype上增加函数
const cbSetCount2 = useCallback(() => {
() => setCount2(count2 + 1);
},[])
return (
<div>
<h1>count1:{count1}</h1>
<button onClick={()=> setCount1(count1+1)}>+</button>
<Child childData={childData} setCount2={cbSetCount2 } />
</div>
)
}
memo手写
const { component } = React;
export default class PureComponent extends Component {
// 如果你需要自定义shouldComponentUpdate 那么就不能继承pureComponent(pureComponent字段该函数)
// 该函数无法鉴定动态的变化
shouldComponentUpdate (nextProps, nextState) {
return !shallowEqual(this.props,nextProps) ||!shallowEqual(this.state,nextState)
}
}
function shallowEqual (o1, o2) {
// 组件不能调用render函数
if (o1 === o2) return true;
if (typeof o1 !== 'object' || o1 === null || typeof o2 !== 'object' || o2 === null) {
return false;
}
const k1 = Object.keys(o1);
const k2 = Object.keys(o2);
if (k1.length !== k2.length) return false;
for (const k of k1) {
if (!o2.hasOwnProperty(k) || o1[k] !== o2[k]) {
return false;
}
}
return true;
}
export function memo (Fc) {
return class extends PureComponent{
return () {
return Fc(this.props)
}
}
}
useMemo
function useMemo(cb,depArr){
if (memoArr[memoIndex]) {
const [_memo, _dep] = memoArr[memoIndex]
const isFullySame = depArr.every((dep, index) => dep === _dep[index]);
if (isFullySame) {
memoIndex++;
return _memo;
} else {
return setNewMemo(cb,depArr)
}
} else {
return setNewMemo(cb,depArr)
}
function setNewMemo (cb, depArr) {
const memo = cb();
memoArr[memoIndex++] = [memo, depArr]
return memo;
}
}
useCallback
function useCallback(cb,depArr){
if (callbackArr[callbackIndex]) {
const [_callback, _dep] = callbackArr[callbackIndex]
const isFullySame = depArr.every((dep, index) => dep === _dep[index]);
if (isFullySame) {
callbackIndex++;
return _callback;
} else {
return setNewCallback(cb,depArr)
}
} else {
return setNewCallback(cb,depArr)
}
function setNewCallback (cb, depArr) {
callbackArr[callbackIndex++] = [cb,depArr]
}
}