React使用hook实现数据双向绑定

写在前面:阅读hook的使用前,要对Class实现方法有一定了解,我们也从这里开始讲起:

const root = ReactDOM.createRoot(document.getElementById('root'));
  
function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  root.render(element);}

setInterval(tick, 1000);

在react初级,我们学会了使用ReactDOM进行元素的挂载、使用jsx模式编辑可视化更强的(<html />)、通过setInterval实现function的调用;如何使用Class进行更加规范性和可编辑性的代码书写呢?在React官方文档有如下的步骤:

  1. 创建一个同名的 ES6 class,并且继承于 React.Component
  2. 添加一个空的 render() 方法。
  3. 将函数体移动到 render() 方法之中。
  4. 在 render() 方法中使用 this.props 替换 props
  5. 删除剩余的空函数声明。

首先,应用Class在我看来是一个必不可少的策略,因为原始的js编辑模式和引入react,使用react DOM进行挂载的方式过分原始,并且缺少作用域的划分,缺少可复用性,甚至在你想要多实现一个功能时变得很被动。

class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

哪怕我们没有对Java足够熟悉,也并不清楚js中类和继承的底层原理,但是直观地,class的出现,让我们很快的想到一个词,那就是“面向对象”。众所周知的时,JS并非面向对象的嫡子,而是在发展后期不断通过新的贡献而看上去(或者说使用上)更加的面向对象,而作为开发程序的工程师,尤其是遇“JS”不久的小白而言,使用是优于理解的,因为只有实践,才是掌握理论的不二法门。

接下来,我们通过一段相同效果的代码来说Class的问题和hook的使用:

import React, { useState } from 'react';

function Example() {
  // 声明一个叫 "count" 的 state 变量  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

诚然,代码行数的减少可以使我们显得更加专业和高级,function的声明也似乎比class extends React.Component 云云更精简,不过真正值得注意的不仅仅于此:

关于this:

有过前端面试经验的小伙伴都清楚,this使用不当是一件很不好的事情,如果你想学好this,可以到掘金刷刷前端经典面试题,或者没事的时候打开Chrome的F12来动手试试,不过在你尚未吃透这个原理的所有场景,或者你单纯就是个谨慎的程序开发者,那么避免在一些可能出错的地方使用this将会是一个很好的选择,Hook的操作最大优点由此显示:通过前端开发的同学们更加熟悉的function写法,避免在各层调用中this指向不准而导致bug的出现;除此之外,通过count, setCount的绑定方法分离state和action层,const阻止变量污染,以上,是我想要分享的hook的优势,接下来将介绍hook的使用方法:useState, useEffect。

(新内容)

关于useState:

基于上述内容,我们已经清楚hook的声明方式:

const [count, setCount] = useState(0); // 0是初始值

我们从这条语句开始说起,const是ES6中对于不可改变的量的声明方式,我们可以清晰地得到“不可以在程序中直接修改count的值"的字面意思,[ ]只是形式不去管他,count和setCount由自己定义,我们习惯于将前面的变量加上set的名称作为其修改方法,useState固定写法,( 0 )是初始值,可以传入js中有实际意义的各类对象,例如对象{}数组[]时间new Date或者一个简单的null。

关于set方法:

第一次接触的同学会有疑问?如何使用修改方法呢,很简单,在相同的上下文内,直接使用setCount(*新的值*),“那上下文...." 还是转化成白话文吧:在当下组件可以直接使用,把useState声明的值当作当前组件的私有变量,如果需要在其他地方使用,请学习如何传值(这是另外一个话题,也可能在接下来一段时间更新到后续文章);

学习到此,我们大概会觉得这个方法好极了,不会被污染,自己私域可用,写法规范,可以绑定到DOM上,等等,记得开始时候我们说得是双向绑定,set方法对应的应该有一个get才对,那么hook的使用方法是什么呢?

异步与副作用:

首先来看一段不简单的代码:

  const [count, setCount] = useState(0);

  setCount(1);
  console.log(count); // 控制台输出:0

好学的你一定知道这是setCount方法的异步性,官方文档给的解释叫做:“useState可能是个异步操作”,如何理解可能不重要,我们不可能将程序置于可能当中,于是官方提供了useState的兄弟方法:useEffect。

关于useEffect:

  const [count, setCount] = useState(0);

  setCount(1);
  console.log(count); // 控制台输出:0

  useEffect(() => {
    console.log(count); // 控制台输出:1
  });

这段代码不做解释,接着来讲:

熟悉vue的同学在开发过程中应当会应用到computed和watch属性,使得页面的数据保持“时时正确”性,很多情况,一个按钮会导致多个展示项的刷新,而延误是我们应当避免的,useEffect就是这样一个方法,他会在react内部启动监听,当某个对象发生改变,触发响应的函数,在这个函数中我们可以使用上述的useState所声明的set方法改变某个绑定到页面的数据项从而渲染新的页面。举手:你刚刚讲的“某个对象”是怎么一回事?

请看这段代码:

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新

OK,当你阅读到这个位置,就已经有相当深入的“入门“知识了,你可以选择新建一个react项目,随便输出几条内容,绑定一两个数据,实践出真知。

接着看代码,我们通常——或者说被规定——使用useEffect(function(), props);的方式来绑定useEffect的监视对象,在上面的例子中,count的值发生改变(by any reason)就会随之进行标题修改的语句。

OK,那么props既然是数组,我们可以传入多条监视源么?No。

使用Effect方法可以解决useState的异步问题么?Yes。

使用Effect方法能实现声明周期函数么?是的,我们将props的内容填空,即[],就会在组件创建之初进行一次且仅一次的调用,类似于Vue中的created声明周期钩子。

useEffect方法有异步性么?无关紧要,因为页面会随着useEffect中的语句更新。

useEffect的实现方式是什么样的?useEffect因为可以监测多个数据源,故一个组件会存在多个use Effect函数,他们会被当做一个整体,也就是一颗方法树,每个新的方法都会挂载在上面,在发生改变之后,整颗树一块刷新,并对应DOM树进行改变。

关于Hook额外的信息:

不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层以及任何 return 之前调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useState 和 useEffect 调用之间保持 hook 状态的正确。(如果你对此感到好奇,我们在下面会有更深入的解释。)

不要在非react代码中使用Hook。

(以上内容类似与考试须知,请大家自行理解)

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值