我的React之路--入门

React的学习之路还要继续走下去,最近一边在做未完成的项目一边学习React,项目是vue写的,后面还需要有一个后台管理系统计划使用react完成,寒假说长也不长,要抓紧时间了。

有人爱有人恨的语法糖--jsx

jsx简介

很多人不喜欢React,很大程度上是因为不喜欢jsx,那么jsx到底是什么呢?首先还是不要忘了React的基本哲学--一切都是js,包括文档结构。所以曾经每天都会见到的html在react的世界里全都不存在,react通过一系列叫做react元素的对象来构建虚拟DOM结构,最原始的创建react元素的方式是这样的:

const root = React.createElement('div',{ className: 'main' },'我是一个div');

最终它将返回一个大概这样子的对象(有所简化过,不代表在 React 源码中是这样):

const root = {
  type: 'div',props: {
    className: 'main',children: '我是一个div'
  }
};

这样一个个创建节点其实是很麻烦的,想想看,如果每个整个虚拟DOM的内容都要通过React.createElement来创建,代码量会很多,而且我们根本无法直观地看出树形结构,无论开发还是维护性都及其不友好。为了解决这一问题,一种新型的,类似xml结构的语法扩展就诞生了,就是jsx。

上面的代码结构改成jsx的书写方式就是这样的:

const root =(
  <div className="main">
      我是一个div
  </div>
);

这个结构就很熟悉了,不过要记住,他不是html模板,它就是js,最终在执行之前会被完全转义成为纯js代码,所以使用jsx是不存在任何性能问题的。

jsx语法

jsx的标准语法结构和xml完全类似,特别的,jsx中的html属性要写成小驼峰命名的形式,比如onclick就要写成onClick。另一点需要注意的问题就是,由于class是js中的保留字,所以要用className来代替。

jsx使用jsx时候要时刻记住它是js表达式,所以它可以像普通的js表达式一样,赋值传参返回都可以。而在jsx内部如果想使用表达式,就需要放在{}里面。这就是jsx语法,非常简单,也不需要记忆特殊的指令,一切都可以和处理js一样来处理,下面来看一个小例子:

const item = this.newsList.map((news,index) => (
    <li key={index}>
      <span>{news.title}</span>
      <span>{news.desc}</span>
      {news.image ? <img src="{news.image}"/> : null}
    </li>
  )
);
const list = (
  <ul>
    {item}
  </ul>
);

这是一个在react开发中特别常见的使用场景,我们得到了一个数组的数据,需要以列表的形式渲染出来。在react中不需要使用任何迭代判断的相关指令语法,只要会写js的都能看懂上面的逻辑:通过数组的map方法迭代数组的内容,在回调函数中处理数据,渲染成想要的样式,就得到了一条一条列表项,插到列表里面就完成数据渲染了。我们可以发现在不论是迭代方法还是三元表达式等等,只要是js语法就可以随意地写到里面,自由度非常高。

可复用的基本单位--组件

为什么要使用组件

了解了jsx,下一个重要概念就是组件了。组件不是react特有的,组件化开发有很多好处,组件符合高内聚低耦合的要求,每一个组件是封装了视图和逻辑的一个相对独立的个体,而整个页面是由多个组件构成的,每个组件可以多次复用。

组件可以理解为类似于函数调用一样,定义好的组件是一个抽象的视图,而我们通过传入相关的“参数”来使它展示出我们想要的样子,组件就是我们复用各种独立部件的基本单位。

React中的组件

定义一个组件最简单的方式是使用JavaScript函数:

function Welcome(props) {
  return <h1>Hello,{props.name}</h1>;
}

这是一个最简单的函数定义组件,整个函数调用结果实际上就是返回一个<h1>标签,不过特别的是,标签的内容不是确定的,它是由我们传入的参数来决定的。这就是组件开发,在React中,最常用的不是函数声明组件,而是向下面一样:

class Welcome extends React.Component {
  render() {
    return <h1>Hello,{this.props.name}</h1>;
  }
}

此处使用了ES6的类和继承,创建了一个继承自Component的类。这个组件和上一个组件效果是完全相同的,下面来重点分析React组件中几个重要的概念。

核心数据状态--state

什么是state?状态,在react组件中,state是指一个组件UI呈现的最小状态集。在react中,视图层的更新是通过处理状态的变化来实现的,而state就是对这一系列状态的定义。react的数据是单向流动的,数据只能从模型层流向视图层,对应到具体的实现,我们对state所做的一系列处理会自动的反映到视图上,我们想要更新视图,只更新状态即可。说的可能比较抽象,看一个具体例子:

class ClickMe extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
  clicked() {
    this.setState({
        count: this.state.count + 1
    });
  }
  render() {
    return (
      <div onClick={() => this.clicked()}>
        点我{this.state.count}次
      </div>
    );
  }
}

这个组件的效果就是点击文字,会显示你的点击次数,效果很简单就不截图了,关于组件生命周期和点击事件绑定后面再看,这里重点来看state的变化。在构造函数里面初始化state的数据,把state数据放在页面上,点击时候调用setState方法改变state中的数据。

关于state有几点需要注意:

  1. state不能直接修改,直接修改state的值是不会更新视图的,正确的更新方式是使用setState来改变state的值。
  2. 不是所有的变量都要放到state中,state里面的变量一方面是要来描述组件自身状态,不需要反映到视图上的内容不是state。
  3. state是最小状态集,取自父组件的状态信息不是自身状态,不能放在state中。从外部传入的东西要放在props中。

外部传递属性--props

props是组件的另一个非常重要的概念,props指的是从外部传入的属性。props是React中父组件向子组件通信的方式,下面是一个简单的例子:

class Child extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div>
        {this.props.data}
      </div>
    );
  }
}

使用组件

<Child data="我是显示的数据"></Child>

我们定义组件时候在构造函数中可以接收到props参数,并且要使用super传到Component的构造方法中。在整个组件的类中就可以使用成员变量props了。而props的内容,是父元素在调用子元素时候以属性的形式传入的。整个props控制的就是从父元素到子元素的事件流,这样我们在使用组件的时候就可以像函数调用一样使用组件,像传入参数一样传入props。

使用props时候要注意一点,props传递数据是单向的,数据只能从父组件传递到子组件,需要其它方向的数据传递就需要使用其他方式了。

组件从创建到销毁--生命周期

生命周期这个概念在很多开发中都会接触,react也是如此,一个react组件从创建运行到销毁需要经历很多阶段,系统也为我们提供了对应阶段的hook方法(hook方法翻译为钩子方法,指的是当组件运行到对应的阶段时候就会自动执行写在这些方法里面的逻辑),我从网上找到了一副描述比较清晰的图片(侵删):

下面来逐一介绍这些生命周期方法以及它们说发挥的作用

  1. getDefaultProps和getInitialState,如果使用ES6的类继承方式定义组件是看不到这两个方法的,它们的任务是组件加载前先获取默认props和初始化state,在ES6的语法中我们可以在constructor中对其进行定义,注意constructor第一句必须要使用super(props),否则会报错。
  2. componentWillMount,在组件渲染之前调用,整个生命周期只会调用一次,子组件的该方法会在父组件调用之后被调用,如果在该方法内设置状态,react会在状态设置好之后才执行渲染,常用在该方法里发送网络请求获取数据。
  3. render(),组件渲染方法,此方法返回组件最终被渲染的状态,它的作用就是渲染组件,此阶段不能修改state。从图上可以看出,除了首次渲染要调用,此方法在组件发生更新时候也会被调用,它是组件最核心的方法。
  4. componentDidMount,在逐渐被渲染之后被调用,仅调用一次,子组件的此方法会在父组件的此方法之前调用,此方法结束后组件进入运行状态。
  5. componentWillReceiveProps(nextProps),组件运行阶段,当组件接收到新的props时被调用,这个函数接收一个object参数(新的props),父组件发生render的时候子组件就会调用,组件首次渲染不会触发。
  6. shouldComponentUpdate(nextProps,nextState),组件运行阶段,接收到新的state或props时被调用,此方法默认返回true,可以通过控制该方法返回false来阻止组件重新渲染。
  7. componentWillUpdate,组件运行阶段,当准备重新渲染组件前调用,做一些渲染前准备工作,组件首次渲染不会触发。
  8. componentDidUpdate,组件运行状态,组件重新渲染之后调用,组件首次渲染不会触发。
  9. componentWillUnmount,在组件被卸载前调用,做一些结束前的清理工作。

以上是react生命周期的相关内容,到此,react组件的基本概念就介绍的差不多了。

行为与交互--事件绑定

在react中绑定事件需要注意一个问题,如果是使用ES6的class方式定义的组件中事件处理函数的this默认是不会绑定的,我们需要手动绑定this指向。来看下面一个错误的例子:

class EventTest extends React.Component {
  clicked() {
    console.log('clicked');
  }
  render() {
    return (
      <div onClick={this.clicked}>
        点我
      </div>
    );
  }
}

点击点我,确实能够正常打印出clicked,看起来好像没有问题,但是,如果试着打印一下this,就会发现结果是undefined。

这样写this没办法绑定,自然也就没办法使用各种成员变量和方法,也不能调用内置方法了,显然不是我们预期的,所以我们需要手动来绑定this指向,方法也很简单:

class EventTest extends React.Component {
  clicked() {
    console.log('clicked');
  }
  render() {
    return (
      <div onClick={this.clicked.bind(this)}>
        点我
      </div>
    );
  }
}

只要增加bind(this)就能实现预期效果了,这也是一种常用的绑定this方式。除此之外还可以采用箭头函数来自动绑定this,下面的做法也是完全可以的:

class EventTest extends React.Component {
  clicked() {
    console.log('clicked');
  }
  render() {
    return (
      <div onClick={()=>this.clicked()}>
        点我
      </div>
    );
  }
}

把clicked作为箭头函数返回的函数来使用,利用箭头函数内部自动绑定this的特性也可以实现this绑定。另外,还有一种写法:

class EventTest extends React.Component {
  clicked = () => {
    console.log('clicked');
  }
  render() {
    return (
      <div onClick={this.clicked}>
        点我
      </div>
    );
  }
}

这种方法是新的ES标准中的实验性语法,由于有babel转译也是可以使用的,官网上面也提到了这种写法,不过由于新的标准还未成熟,所以用的人也不多。

了解了这些,react算是入了门了,接下来深入学习的路还长,虚拟DOM的原理,diff算法,css-in-js,工程化下的react项目结构,react-router,redux,还有以后要学习的react native,后面随着学习慢慢总结。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom