做课件用这15大网站,ai论文生成器免费,网站推广上首页,wordpress建app组件基础
回顾下React中创建组件的几种方式#xff1a;
ES5的React.createClass方式ES6的React.Component方式无状态的函数组件方式带hooks的函数组件方式 这里我们只讨论Component和函数组件。我们知道Component是否发生重渲染是由shouldComponentUpdate决定的#xff0c;…组件基础
回顾下React中创建组件的几种方式
ES5的React.createClass方式ES6的React.Component方式无状态的函数组件方式带hooks的函数组件方式 这里我们只讨论Component和函数组件。我们知道Component是否发生重渲染是由shouldComponentUpdate决定的默认情况下返true。自定义的Component会根据自身state和props是否发生变化来决定自身是否需要重新渲染这个过程往往需要进行深度比较的。而相对应的PureComponent会通过shadowEqual对state和props进行浅比较来决定是否需要重新渲染。一般而言如果state和props没有发生变化组件本身是不需要重新渲染的。 Component组件的渲染过程是组件调用自身的render函数来生成虚拟DOM然后跟上次的进行比较如果发生变化就更新对应的平台DOM。React平台以及第三方库提供的组件一般都是基于Component的因此只要确保props不变就不会重新渲染。 而对于函数组件只要这个函数被调用虚拟DOM就会重新生成。从这个角度来看函数是否执行跟传给它什么参数是无关的。只是取决于它所在父Component组件是否调用了render函数或者父函数组件是否被调用了。 useState这个hooks为函数组件提供了状态保持和触发渲染的功能。我们知道作为纯函数本身它内部是无法持久存储一个值的每次函数执行完毕里面创建的所有变量都会被清除。所以useState本质是把状态保存到了函数外部这样每次执行函数既能修改保存它的值也能获取上次执行后的值。
一个React例子 接下去看一个例子我们可以把代码拷贝到安装 – React 中文文档 的尝试 React中
import {useState} from reactconst Parent () {const [count, setCount] useState(0);const [son1Count, setSon1Count] useState(0);const [son2Count, setSon2Count] useState(0);return (div{console.log(Parent render)}button onClick{() setCount(v v 1)}Parent 1/buttonbutton onClick{() setSon1Count(v v 1)}Son1 1/buttonbutton onClick{() setSon2Count(v v 1)}Son2 1/buttonh3Parent: {count}/h3Son1 son1Count{son1Count} /Son2 son2Count{son2Count} //div);
};
const Son1 (props) {return (div{console.log(Son1 render)}Son1: {props.son1Count}/div);
};
const Son2 (props) {return (div{console.log(Son2 render)}Son2: {props.son2Count}/div);
};export default function App() {return Parent /
}
按照我们前面的描述点击parent1按钮会导致Parent组件重新执行因此Son1和Son2尽管props没有发生变化但由于它们是函数组件它们依然会被执行。
使用memo
memo 允许你的组件在 props 没有改变的情况下跳过重新渲染。我们可以用它来改造上面的Son1和Son2
const Son1 memo((props) {return (div{console.log(Son1 render)}Son1: {props.son1Count}/div);
});
const Son2 memo((props) {return (div{console.log(Son2 render)}Son2: {props.son2Count}/div);
现在我们再点击parent1就会发现Son1和Son2没有重新执行了。 props中包含函数
更新我们的例子向memo后的Son组件props传递一个函数
import {useState ,memo} from react
const Parent () {const [count, setCount] useState(0);const [sonCount, setSonCount] useState(0);const allPlus () {setCount(v v 1);setSonCount(v v 1);};return (div{console.log(Parent render)}button onClick{() setCount(v v 1)}Parent 1/buttonh3Parent: {count}/h3Son allPlus{allPlus} sonCount{sonCount} //div);
};
const Son memo((props) {return (div{console.log(Son render)}pSon: {props.sonCount}/pbutton onClick{props.allPlus}All 1/button/div);
});export default function App() {return Parent /
}
尽管我们使用了memo但当我们点击parent1按钮时Son也发生了渲染。问题的根源是Parent组件每次执行时里面的allPlus函数会重新创建导致Son的props发生了变化。默认情况下React 将使用 Object.is 比较每个 prop。
memo的arePropsEqual
一个解决办法是我们实现memo的第二个参数arePropsEqual以取代默认的实现
const Son memo((props) {return (div{console.log(Son render)}pSon: {props.sonCount}/pbutton onClick{props.allPlus}All 1/button/div);
},
(prevProps, nextProps) prevProps.sonCount nextProps.sonCount);再点击parent1按钮我们发现Son不再重新渲染了。
useCallback
另一个解决办法是保持函数的不变性在React中我们通常使用useCallback在多次渲染中缓存函数。它的作用看起来和useRef类似但它还提供了第二个参数dependencies用来在依赖发生改变时更新以及返回这一次渲染传入的函数。将代码更新如下
const allPlus useCallback(() {setCount(count 1);setSonCount(sonCount 1);
}, []);
这时候点击parent1按钮也不会引起Son组件重新渲染。
useMemo
保持函数的不变性我们也可以使用useMemo。useMemo缓存的是函数执行的结果。因为我们要缓存一个函数因此我们要使用一个返回这个函数的函数作为useMemo的参数修改代码如下
const allPlus useMemo(() () { // 注意这里不同于 useCallbacksetCount((v) v 1);setSonCount((v) v 1);},[]);
memo和useMemo的区别
对于一个函数组件useMemo可以缓存它的执行结果而不是函数组件本身。而memo 是高阶组件它会比较当前组件的 props 和 state 是否发生了变化如果都没有变化就不会重新渲染该组件而是直接使用之前的结果。但是memo组件本身每次渲染时都会重新创建。因此当我们需要保证组件不被重复渲染时使用memo。当需要保证组件prop的不变性时使用useMemo。
一个React Native例子
假设我们有一个FlatList并且支持下拉刷新因此给它设置了refreshControl。并且在滚动的时候控制一个”返回顶部“按钮的显示与隐藏。
const App () {const [refreshing, setRefreshing] React.useState(false);const flatListRef useRefFlatList(null)const [showTop, setShowTop] useState(isShowTop)const onRefresh React.useCallback(() {setRefreshing(true);wait(2000).then(() setRefreshing(false));}, []);const handleScrollToTop () {flatListRef.current?.scrollToOffset({ animated: true, offset: 0 })}const onScroll (e: NativeSyntheticEventNativeScrollEvent) {const scrollY e.nativeEvent.contentOffset.yif (scrollY 0) {setShowTop(true)} else {setShowTop(false)}}, [])return (SafeAreaView style{styles.container}FlatListref{flatListRef}data{DATA}onScroll{onScroll}renderItem{({item}) Item title{item.title} /}keyExtractor{item item.id}refreshControl{RefreshControl refreshing{refreshing} onRefresh{onRefresh} /}/{showTop Button onPress{handleScrollToTop} titleTop/Button}/SafeAreaView);
};
当调用setShowTop时APP组件会发生重新渲染。这里的onScroll、renderItem、refreshControl都会重新创建导致FlatList重新渲染。使用前面我们提到的技巧当然renderItem可以移动到App函数外面去我们可以缓存这些prop来避免发生变化。对于refreshControl我们可以使用useMemo例如
const refreshControl useMemo(() RefreshControl refreshing{refreshing} onRefresh{onRefresh} /, [refreshing])
当然我们常见的代码大多数使用我们一开始提供的版本因为大多数情况下多余的渲染并不会引起显著的性能问题。但是理解并发现多余的渲染有助于我们在必要时进行相应的优化。 参考
https://www.cnblogs.com/hymenhan/p/16325708.html