一篇对DanHow Are Function Components Different from Classes? 一文的个人阅读总结,内容来自于此。强烈推荐阅读 Dan Abramov.的博客

函数式组件和Class组件有什么不同?

Dan很直接的给出了答案:

函数式组件捕获了渲染所用的值。(Function components capture the rendered values.)

直接看结论可能有点不知所云。

class组件可能引发的"错误"

看一个组件,使用setTimeout模拟网络请求,点击button之后警告提示关注某人(user),userprops中读取。

该组件的function版本:

function ProfilePage(props) {
const showMessage = () => {
alert('Followed ' + props.user);
}; const handleClick = () => {
setTimeout(showMessage, 3000);
}; return (
<button onClick={handleClick}>Follow</button>
);
}

class版本:

 class ProfilePage extends React.Component {
showMessage = () => {
alert('Followed ' + this.props.user);
}; handleClick = () => {
setTimeout(this.showMessage, 3000);
}; render() {
return <button onClick={this.handleClick}>Follow</button>;
}
}

页面组件代码:

class App extends React.Component {
state = {
user: 'Dan',
};
render() {
return (
<>
<label>
<b>Choose profile to view: </b>
<select
value={this.state.user}
onChange={e => this.setState({ user: e.target.value })}
>
<option value="Dan">Dan</option>
<option value="Sophie">Sophie</option>
<option value="Sunil">Sunil</option>
</select>
</label>
<h1>Welcome to {this.state.user}’s profile!</h1>
<p>
<ProfilePageFunction user={this.state.user} />
<b> (function)</b>
</p>
<p>
<ProfilePageClass user={this.state.user} />
<b> (class)</b>
</p>
<p>
Can you spot the difference in the behavior?
</p>
</>
)
}
}

对于class组件,在选中状态是userA的时候,点击follow button之后立马将select切换其他人(uerB),三秒之后的弹出框是followuserB。(这个动作会在后面多次提及)

在选中userA的时候点击关注,目的就是关注userA,但是class组件最后弹出框显示的关注userB,这显然不符合预期。

为什么、如何解决

如果上面例子使用function组件,弹出框显示的就会是正确的,虽然切换到了选中的userB,但是弹出框显示的仍然是点击的那一刻关注的userA

function组件好像记下了点击那一刻时候的状态?

class组件在这个场景中错误的原因是class组件每次三秒后从this.props.user中读取数据,此时的this.props.user已经变了,已经是切换后的新的this.props.user数据。虽然React中props不可变,但是this是可变的

类组件会随着时间推移改变,在渲染方法和生命周期方法中得到的是最新的实例。而函数式组件的事件处理程序就是渲染结果的一部分,事件处理程序属于一个拥有特定的propsstate的渲染

也就是说函数式组件保持了事件处理程序与那一次渲染propsstate之间的联系,本身就是正确的。


来修复类组件中的这个问题:

  1. 可以在点击的时候就读取并记录当下的stateprops,三秒后读取记录的数据(而不是读this.props.xx)再弹出。

    方案可行但是扩展极差,在其他多个变量也这样做的时候逐层记录或传递非常繁复。

  2. 闭包。

    闭包维持了一个可能随时间变化的变量,而此处我们要维持的是React的propsstate,React设计中这都是不可变的。让闭包来维持不变的stateprops,此时再去捕获这些值,就是一致的。

    render函数中使用闭包:

    class ProfilePage extends React.Component {
    render() {
    // Capture the props!
    const props = this.props; // Note: we are *inside render*.
    // These aren't class methods.
    const showMessage = () => {
    alert('Followed ' + props.user);
    }; const handleClick = () => {
    setTimeout(showMessage, 3000);
    }; return <button onClick={handleClick}>Follow</button>;
    }
    }

    渲染的时候这些需要使用的props已经被捕获(就像上面方案1的记录,在render的时候就已经读取记录下了)。此时表现弹出内容就会是点击时候的那个userA了。


class组件的这个问题是修复了,但是在render函数中添加那么多的函数,且并没有挂载到class上,有点奇怪?

其实去掉class,这就是函数式组件的形式了:

function ProfilePage(props) {
const showMessage = () => {
alert('Followed ' + props.user);
}; const handleClick = () => {
setTimeout(showMessage, 3000);
}; return (
<button onClick={handleClick}>Follow</button>
);
}

React将他们作为参数传递,props在渲染时被捕获了。不同于class组件的this,这里的props不会被改变。

点击事件处理函数,该函数属于具有正确user值的一次渲染,事件处理函数和其他回调函数也能读到这个值。

回头看这个结论,是不是更好理解一点了:

函数式组件捕获了渲染所使用的值

函数式组件使用最新的propsstate

函数式组件捕获了特定渲染的propsstate。但是我们如果又想和class组件一样读取最新的propsstate呢?

useRef

Dan 老师:在函数式组件中,你也可以拥有一个在所有的组件渲染帧中共享的可变变量。它被成为“ref”

this.something就像是something.current的一个镜像。他们代表了同样的概念。

每一次的渲染结果可以视为一个渲染帧,共享的变量设置为ref,包含DOMRefclass中的实例变量的功能,可以说是非常强大了。

需要最新的propsstate值,可以使用useRef创建的变量来记录,通过useEffect可以在值变化的时候自动追踪。

function MessageThread() {
const [message, setMessage] = useState(''); // 保持追踪最新的值。
const latestMessage = useRef('');
useEffect(() => {
latestMessage.current = message;
}); const showMessage = () => {
alert('You said: ' + latestMessage.current);
};

React函数总是捕获他们的值

React函数式组件和类组件[Dan]的更多相关文章

  1. React - 组件:类组件

    目录: 1. 类组件有自己的状态 2. 继承React.Component-会有生命周期和this 3. 内部需要一个render函数(类组件会默认调用render方法,但不会默认添加,需要手动填写r ...

  2. React Native知识5-Touchable类组件

    React Native 没有像web那样可以给元素绑定click事件,前面我们已经知道Text组件有onPress事件,为了给其他组件 也绑定点击事件,React Native提供了3个组件来做这件 ...

  3. React函数类组件及其Hooks学习

    目录 函数类组件 函数式组件和类式组件的区别: 为什么要使用函数式组件? Hooks概念及常用的Hooks 1. useState: State的Hook 语法 useState()说明: setXx ...

  4. React中的高阶组件,无状态组件,PureComponent

    1. 高阶组件 React中的高阶组件是一个函数,不是一个组件. 函数的入参有一个React组件和一些参数,返回值是一个包装后的React组件.相当于将输入的React组件进行了一些增强.React的 ...

  5. React 深入系列2:组件分类

    文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列2:组件分类 React 深入系列,深入讲解了React中的重点概念.特性和模式等,旨在帮助大家加 ...

  6. 【React】react学习笔记02-面向组件编程

    react学习笔记02-面向组件编程 面向组件编程,直白来说,就是定义组件,使用组件. 以下内容则简单介绍下组建的声明与使用,直接复制demo观测结果即可. 步骤: 1.定义组件   a.轻量组件-函 ...

  7. 如何对 React 函数式组件进行优化

    文章首发个人博客 前言 目的 本文只介绍函数式组件特有的性能优化方式,类组件和函数式组件都有的不介绍,比如 key 的使用.另外本文不详细的介绍 API 的使用,后面也许会写,其实想用好 hooks ...

  8. React函数式组件使用Ref

    目录: 简介 useRef forwardRef useImperativeHandle 回调Ref 简介 大家都知道React中的ref属性可以帮助我们获取子组件的实例或者Dom对象,进而对子组件进 ...

  9. React函数式组件的性能优化

    优化思路 主要优化的方向有2个: 减少重新 render 的次数.因为在 React 里最重(花时间最长)的一块就是 reconction(简单的可以理解为 diff),如果不 render,就不会 ...

随机推荐

  1. fiddler抓包+安卓机 完成手机app抓包的配置 遇到的一些问题

    fiddler抓包+安卓模拟器完成手机app抓包的配置:fiddler抓包+雷电模拟器 完成手机app抓包的配置 其实在安卓真机上弄比在虚拟机上弄更麻烦一点,它们的步骤都差不多一样,就是在安卓真机上弄 ...

  2. Codeforces Round #479 (Div. 3) E. Cyclic Components (思维,DFS)

    题意:给你\(n\)个顶点和\(m\)条边,问它们有多少个单环(无杂环),例如图中第二个就是一个杂环. 题解:不难发现,如果某几个点能够构成单环,那么每个点一定只能连两条边.所以我们先构建邻接表,然后 ...

  3. 功能按钮发post请求 参数放入body中

    1.功能按钮事件参数 queryBody_ids:{data.ids} 前端会生成下划线后面的编码ids,并替换{data.ids} 2.后端建参数model后端参数可以只包含前端返回的部分参数 [D ...

  4. leetcode32 最长游戏括号 dp

    有一说一,我觉得这题没有到困难级 要保存之前的状态,感觉是很明显的dp 思路和题解一样 class Solution { public: int longestValidParentheses(str ...

  5. np.random.randint()的返回值

    返回的是数组而非int 比如返回x,y 为[1][2] 而非1,2 容易在只有一维一列时没有意识到 其他函数的返回值也要注意

  6. MD5强碰撞

    关卡一         md5弱比较,为0e开头的会被识别为科学记数法,结果均为0 payload param1=QNKCDZO&param2=aabg7XSs 关卡二         md5 ...

  7. Vue 组件之间通信 All in One

    Vue 组件之间通信 All in One 组件间通信 1. 父子组件之间通信 https://stackblitz.com/edit/vue-parent-child-commutation?fil ...

  8. SQL Tutorials & MySQL & SQL Server

    SQL Tutorials SQL MySQL https://www.mysql.com/ $ mysql --version # mysql Ver 8.0.21 for osx10.15 on ...

  9. where is the storage location of the browser's HTTP cache? disk or memory

    where is the storage location of the browser's HTTP cache? disk or memory HTTP cache & storage l ...

  10. react hooks & component will unmount & useEffect & clear up

    react hooks & component will unmount & useEffect & clear up useEffect & return === u ...