一、业务场景
-
1、使用类定义一个父组件
export default class Parent extends React.Component { state = { count: 0, } render() { return( <div> 我是父组件 <button onClick={() => this.setState({count: this.state.count++})}>点击按钮</button> <Child /> </div> ) } }
-
2、定义一个子组件
class Child extends React.Component { render() { console.log('我是子组件'); return ( <div> 我是子组件 <Grandson /> </div> ) } }
-
3、定义一个孙子组件
class Grandson extends React.Component { render() { console.log('孙子组件') return(<div>孙子组件</div>) } }
-
4、上面几个组件是比较标准的
react
的类组件,函数组件也是类似的,当你在父组件中点击按钮,其实你仅仅是想改变父组件内的count
的值,但是你会发现每次点击的时候子组件和孙组件也会重新渲染,因为react
并不知道是不是要渲染子组件,需要我们自己去判断。
一、类组件中使用shouldComponentUpdate
生命周期钩子函数
-
1、在子组件中使用
shouldComponentUpdate
来判断是否要更新,class Child extends React.Component { shouldComponentUpdate (nextProps, nextState) { console.log(nextProps, this.props); if (nextProps.count === this.props.count) { return false; } else { return true; } } ... }
**注意点:**这里的
count
是要父组件给当前组件传递的参数(就是你要监听变化的的来更新当前组件),如果你写一个nextProps.name === this.props.name
其实,父组件并没有给当前组件传递name
那么下面都是返回false
组件不更新 -
2、当子组件没更新,那么孙组件同样的不更新数据
二、使用PureComponet
语法糖
-
1、子组件中继承
class Child extends React.PureComponent { render() { console.log('我是子组件'); return ( <div> 我是子组件 <Grandson /> </div> ) } }
-
2、在父组件中使用
// 下面这种情况不会重新渲染子组件 <Child/> // 下面这种情况下会重新渲染子组件 <Child count={this.state.count}/>
三、memo
的使用
-
1、组件定义(这里也可以使用类组件)
function Child () { console.log('我是子组件'); return ( <div> 子组件 </div> ) } function Parent () { const [count, setCount] = useState(0); return ( <div> 我是父组件-{count} <button onClick={()=>setCount(count + 1)}>点击按钮</button> <Child /> </div> ) }
-
2、这里我们父组件内部改变
count
并没有传递给子组件,但是子组件一样的重新渲染了,这并不是我们希望看到的,因为需要对子组件包装下function Child () { console.log('我是子组件'); return ( <div> 子组件 </div> ) } const ChildMemo = React.memo(Child); function Parent () { const [count, setCount] = useState(0); return ( <div> 我是父组件-{count} <button onClick={()=>setCount(count + 1)}>点击按钮</button> {/* 这种情况下不会渲染子组件 */} <ChildMemo /> {/* 这种情况下会渲染子组件 */} <ChildMemo count={count}/> </div> ) }
四、useMemo
和useCallback
的认识
-
1、
useMemo
和useCallback
都是具有缓存作用的,只是他们缓存对象不一样,一个是属性,一个是缓存函数,特点都是,当缓存依赖的没变,去获取还是获取曾经的缓存 -
2、
useMemo
是对函数组件中的属性包装,返回一个具有缓存效果的新的属性,当依赖的属性没变化的时候,这个返回新属性就会从缓存中获取之前的。 -
3、
useCallback
是对函数组件中的方法缓存,返回一个被缓存的方法
五、useMemo
的使用(我们依赖借用子组件更新的来做)
-
1、根据上面的方式我们在父组件更新数据,观察子组件变化
const Child = (props) => { console.log('重新渲染子组件', props); return ( <div>子组件</div> ) } const ChildMemo = React.memo(Child); const Parent = () => { const [count, setCount] = useState(0); const [number, setNumber]=useState(0) const userInfo = { age: count, name: 'hello', } const btnHandler = () => { setNumber(number+1); } return ( <div> {number}-{count} <button onClick={btnHandler}>按钮</button> <ChildMemo userInfo={userInfo}/> </div> ) }
上面发现我们仅仅是更新了
number
的值,传递给子组件的对象值并没有变化,但是每次子组件都重新更新了,虽然我们在子组件上用了React.memo
包装还是不行,这是因为在父组件中每次重新渲染,对于对象来说会是重新一个新的对象了。因此子组件要重新更新, -
2、使用
useMemo
对属性的包装const userInfo = useMemo(() => { return { age: count, name: 'hello', }; }, [count]);
使用
useMemo
包装后的对象,重新返回一个具有缓存效果的新对象,第二个参数表示依赖性,或者叫观察对象,当被观察的没变化,返回的就是缓存对象,如果被观察的变化了,那么就会返回新的,现在不管你怎么更新number
的值,子组件都不会重新更新了 -
3、注意点:
useMemo
要配合React.memo
来使用,不然传递到子组件也是不生效的
六、useCallback
的使用
前面介绍了,useCallback
是对一个方法的包装,返回一个具有缓存的方法,常见的使用场景是,父组件要传递一个方法给子组件
-
1、在不使用
useCallback
的时候const Child = (props) => { console.log('渲染了子组件'); const { onClick } = props; return ( <button onClick={onClick}>点击按钮获取值</button> ) } const ChildMemo = React.memo(Child); const Parent = () => { const [text, updateText] = useState(''); const textRef = useRef(text); const handleSubmit = () => { console.log('当前的值', text); } return( <div> 我是父组件 <input type="text" value={text} onChange={(e) => updateText(e.target.value)}/> <ChildMemo onClick={handleSubmit}/> </div> ) }
结果是每次输入框输入值的时候,子组件就会重新渲染一次,其实子组件中仅仅是一个按钮,要获取最终输入的值,每次父组件输入值的时候,子组件就更新,很耗性能的
-
2、使用
useCallback
来包装一个方法const Parent = () => { const [text, updateText] = useState(''); const textRef = useRef(); // useCallback又依赖了textRef的变化,因此可以获取到最新的数据 const handleSubmit = useCallback(() => { console.log('当前输入框的值:', textRef.current); }, [textRef]) // 当text的值变化的时候就会给textRef的current重新赋值 useEffect(() => { textRef.current = text; }, [text]); return( <div> 我是父组件 <input type="text" value={text} onChange={(e) => updateText(e.target.value)}/> <ChildMemo onClick={handleSubmit}/> </div> ) }
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!