使用hook时,把携带setState的方法通过props传给子类组件,调用不生效? 您所在的位置:网站首页 react传递函数 使用hook时,把携带setState的方法通过props传给子类组件,调用不生效?

使用hook时,把携带setState的方法通过props传给子类组件,调用不生效?

2024-02-21 10:10| 来源: 网络整理| 查看: 265

一、问题来源

为了学习React的HOOK,我实现了一个简单的计数器,但是把动态修改计数器count的方法通过props传递给子组件时,出现了只生效一次,再次调用不生效的问题。

二、场景介绍

父组件是一个函数式组件,使用了useState来动态更新Count。子组件是类组件,通过父组件传递的回调函数props.changeCount来修改父组件的count。但是出现了调用changeCount不生效的奇怪现象。下面是出现问题的代码,大家可以先分析下问题出在了哪里。

import React,{useState} from 'react'; class FancyButton extends React.Component { handleClick = this.props.changeCount render() { return ( this.props.label} ) } } function App() { const [count, setCount] = useState(0); const changeCount=()=>{ setCount(count + 1 ) } return ( {count} constructor(props){ super(props); //其实这段代码和上面的代码是一样的效果,只不过语法上的改变 //但是这样写就很容易找到问题的所在 this.handleClick = this.props.changeCount; } handleClick = this.props.changeCount render() { return ( this.props.label} ) } }

这样简单改造后,我们可能就能之间发现问题所在,下面先介绍为什么第一次点击的时候会成功,然后再说明为什么再次点击的时候会失败。

为什么第一次点击的时候会成功? 学习过react声明周期函数的同学肯定知道constructor函数只会在组件第一次初始化的时候调用一次,所以整个程序初始化的时候我们把父组件的changeCount函数赋值给FancyButton的handleClick进行绑定,所以第一次点击按钮的时候一定会成功。为什么再次点击的时候无效? 现在我们把关注点放在第一次点击后发生了什么react内部发生了什么事情,首先点击后间接触发了setCount()函数修改了Count的值,此时App组件中的 state发生了改变导致重新渲染,其实就是再从头到位执行一遍App这个函数,那么意味着App再次执行前后changeCount函数不是一个函数了,并且每次重新执行count的值仍然是1 由于React性能优化的机制,自组件并不能监测到props.changCount发生了改变,所以此时组件FancyButton中的this.handleClick引用的仍然是第一次constructor初始化式绑定的changeCount,这样不仅会造成this.handleClick失去了绑定,而且还造成了内存泄漏😂; 解决方案 采用函数式更新state 仍然在构造函数中绑定changeCount,修改App组件中的changeCount函数,采用函数式更新state,这样做的原因利用Hook闭包的原理,每次更新调用的setCount函数中传递的prev更新Count,而这prev是从hook的闭包环境中获取的值,所以每次点击都会改变。function App() { const [count, setCount] = useState(0); const changeCount=()=>{ console.log(count);// 0 //采用函数式更新 setCount(prev=>prev+1) } return ( {count} render() { //在此处进行赋值绑定 this.handleClick = this.props.changeCount return ( this.props.label} ) } } 惯用的写法(闭包) 这样做是constructor执行是生成一个箭头函数保存对this.props.changeCount()这个方法的引用,实质上是利用闭包的原理,所以每次调用相当于在App调用changeCount()这函数。class FancyButton extends React.Component { //这样做实质上是引用了App中的值(函数也是值),产生了闭包 handleClick =()=>this.props.changeCount() render() { return ( this.props.label} ) } } function App() { const [count, setCount] = useState(0); const changeCount=()=>{ //每次打印都是0 console.log(count);// 0 setCount(count + 1) } return ( {count} const [count, setCount] = useState(0); const changeCount=()=>{ //每次结果都是期望的结果0,1,2... //至于为什么,请去阅读一下官方文档HOOK规则,此处不再赘述 console.log(count);// 0->1->2... //注意此处还是赋值式更新 setCount(count + 1) } return ( {count}


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有