React学习(一)——初步了解,完成ToDoList功能demo

React学习笔记(一)

自用

文章目录

  • React学习笔记(一)
    • 1. React简介
    • 2. 前端三大主流框架
      • React vs Vue
      • React的优势
    • 3. React基础知识
      • JSX语法
        • 为什么使用 JSX?
      • React 组件
      • 虚拟DOM
      • Diff算法
      • 基础语法
        • React.Component
        • ReactDOM.render
    • 4. 完成一个简单的demo——TodoList
      • 前期:完善功能
      • 中期:组件拆分
      • 后期代码优化,调整样式
    • 5. React衍生产物
      • React Native
      • React VR
      • React Fiber
    • 6. 个人小结

1. React简介

React是一个用于构建用户界面的JavaScript库,主要用于构建UI。React强调的是面向数据编程。

React起源于Facebook的内部项目,起初是因为该公司对所有JavaScript MVC(Model View Controller 模型-视图-控制器)框架都不满意,所以决定自己写一套来架设Instagram网站,后来觉得这套框架很好用,就在2013年五月进行开源推出。其带来了一种全新的函数式编程风格,React的设计思想极其独特,属于革命性创新,性能出众,代码逻辑非常简单,是目前最流行的前端框架。

React 是一个全新思路的前端 UI 框架,它完全接管了 UI 开发中最为复杂的局部更新部分,擅长在在复杂场景下保证高性能;同时,它引入了基于组件的开发思想,从另一个角度来重新审视 UI 的构成。通过这种方法,不仅能够提高开发效率,而且可以让代码更容易理解,维护和测试。

React特点

  • 声明式
    • React 使创建交互式 UI 变得轻而易举。为你应用的每一个状态设计简洁的视图,当数据改变时 React 能有效地更新并正确地渲染组件。
    • 以声明式编写 UI,可以让你的代码更加可靠,且方便调试。
  • 组件化
    • 创建拥有各自状态的组件,再由这些组件构成更加复杂的 UI。
    • 组件逻辑使用 JavaScript 编写而非模版,因此你可以轻松地在应用中传递数据,并使得状态与 DOM 分离。
  • 一次学习,随处编写
    • 无论你现在正在使用什么技术栈,你都可以随时引入 React 来开发新特性,而不需要重写现有代码。
    • React 还可以使用 Node 进行服务器渲染,或使用 React Native 开发原生移动应用。

2. 前端三大主流框架

library(库):小而巧。船小好调头,可以很方便的从一个库切换到另外的库,但是代码几乎不会变。

Framework(框架):大而全。框架提供了一整套的解决方案,如果在项目中,想切换到另外的框架,会比较困难。

  • Angular:2009年推出,被Google收购。学习曲线较长较陡,框架偏重(Angular1与之后的Angular2、Angular3…有断层)已逐渐被淘汰。
  • React:2013年推出,得益于其创新式的Virtual DOM,性能出众,一经推出,非常火爆。采用函数式编程,门槛稍高,但也更灵活,能让开发具有更多可能性,是目前使用人数最多的框架,具有健全的文档和完善的社区
  • Vue:2014年推出的轻量级框架由中国人尤雨溪开发,借鉴了前辈angular和react的特点,使其使用起来更加方便,更容易上手,比较适合初学者,是目前关注人数最多的框架

React vs Vue

Vue的API设计非常简洁,但是其实现方式却让人感觉是“魔法”,开发者虽然能马上上手,但是为什么能实现功能却很难说清楚。

相比之下React的设计哲学非常简单,虽然经常有需要自己处理各种细节问题,但是却让人感觉它非常“真实”,能清楚地感觉到自己仍然是在写js。

React与Vue中心思想相同:一切都是组件,组件实例之间可以嵌套。

组件化方面

  • 组件写法不一样, React推荐的做法是 JSX , 也就是把HTML和CSS全都写进JavaScript了,即’all in js’;
  • Vue推荐的做法是webpack+vue-loader的单文件组件格式,即html,css,js写在同一个文件;

数据流方面

  • React是单向数据流,代码写起来会较双向数据流的多一些,但是同样的排查问题时思路清晰很多;
  • Vue是双向数据流;

开发团队方面

  • React是由FaceBook前端官方团队进行维护和更新的; 因此,React的维护开发团队,技术实力比较雄厚;

  • Vue:第一版,主要是有作者尤雨溪专门进行维护的,当Vue更新到2.x版本后,也有了一个以尤雨溪为主
    导的开源小团队,进行相关的开发和维护;

社区方面

  • 在社区方面,React由于诞生的较早,所以社区比较强大,一些常见的问题、坑、最优解决方案,文档、博客
    在社区中都是可以很方便就能找到;
  • Vue由于起步时间较晚,Vue的社区相对于React来说,要小一些,相对没有React的成熟与完善;

移动APP开发体验方面

  • Vue, 结合Weex这门技术,提供了迁移到移动端App开发的体验(Weex, 目前只是一 个小的玩具, 并没
    有很成功的大案例;
  • React, 结合ReactNative,也提供了无缝迁移到移动App的开发体验(RN用的最多,也是最火最流行的) ;

React的优势

  1. 声明式设计,使用虚拟DOM的概念,性能好,速度快。虚拟DOM帮助解决了跨浏览器问题,并为我们提供了标准化的API
  2. 复用性高,代码一切皆是组件,更加模块化,重用代码更容易,可维护性高。
  3. 高效,纯粹的javascript代码预渲染应用,有助于搜索引擎优化。
  4. 灵活,React只是MVC中的View层,自己无法构建大型的应用,需要与已有的框架和库来配合,如:Flux(前端架构) 、Redux(状态管理)、Axios/Fetch(异步请求)等。

3. React基础知识

JSX语法

JSX, 一种 JavaScript 的语法扩展,其格式比较像是模版语言,但事实上完全是在JavaScript内部实现的,它允许 HTML 与 JavaScript 的混写。通常在 React 中使用 JSX 来描述用户界面。 元素是构成 React 应用的最小单位,JSX 就是用来声明 React 当中的元素。

React不一定要使用 JSX,但它有以下优点:

  • JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
  • 它是类型安全的,在编译过程中就能发现错误。
  • 使用 JSX 编写模板更加简单快速。

JSX 看起来类似 HTML:

ReactDOM.render(
    

Hello, world!

, document.getElementById('example') );

为什么使用 JSX?

React 认为渲染逻辑本质上与其他 UI 逻辑内在耦合,比如,在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据。

React 并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为“组件”的松散耦合单元之中,来实现关注点分离

React 不强制要求使用 JSX,但是大多数人发现,在 JavaScript 代码中将 JSX 和 UI 放在一起时,会在视觉上有辅助作用。它还可以使 React 显示更多有用的错误和警告消息。

React 组件

React.JS是基于组件化的开发,React框架允许我们将代码封装成组件,然后像插入普通的HTML标签一样,在网页中插入这个组件。

  • 组件的第一个字母必须大写
  • return中的内容需要用一个大的闭合标签整个包裹起来
//index.js
//引入 React 库
import React from 'react';
import ReactDOM from 'react-dom';
// 引入App组件,以大写字母开头
import App from './App';
//App.js
import React from 'react';
//定义一个React组件
function App() {
     
  return (
    <div className="App">
      Hello World!
    </div>
  );
}

export default App;

在JS中通过React将App组件渲染到页面上

image-20191215155808154

React 认为一个组件应该具有如下特征:

(1)可组合(Composeable):一个组件易于和其它组件一起使用,或者嵌套在另一个组件内部。如果一个组件内部创建了另一个组件,那么说父组件拥有(own)它创建的子组件,通过这个特性,一个复杂的 UI 可以拆分成多个简单的 UI 组件;

(2)可重用(Reusable):每个组件都是具有独立功能的,它可以被使用在多个 UI 场景;

(3)可维护(Maintainable):每个小的组件仅仅包含自身的逻辑,更容易被理解和维护;

(4)可测试(Testable):因为每个组件都是独立的,那么对于各个组件分别测试显然要比对于整个 UI 进行测试容易的多。

虚拟DOM

文档对象模型(Document Object Model,简称DOM

1.什么是Virtual DOM

虚拟DOM概念随着react的诞生而诞生,由facebook提出,其卓越的性能很快得到广大开发者的认可。

Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存。可以类比 CPU 和硬盘,既然硬盘这么慢,我们就在它们之间加个缓存:既然 DOM 这么慢,我们就在它们 JS 和 DOM 之间加个缓存。CPU(JS)只操作内存(Virtual DOM),最后的时候再把变更写入硬盘(DOM)。

2.为什么要用Virtual DOM

在浏览器里一遍又一遍的渲染DOM是非常非常消耗性能的,常常会出现页面卡死的情况;所以尽量减少对DOM的操作成为了优化前端性能的必要手段,Virtual DOM就是将DOM的对比放在了js层,通过对比不同之处来选择新渲染DOM节点,从而提高渲染效率。

在传统的 Web 应用中,我们往往会把数据的变化实时地更新到用户界面中,于是每次数据的微小变动都会引起 DOM 树的重新渲染。

虚拟DOM的目的是将所有操作累加起来,统计计算出所有的变化后,统一更新一次DOM,最终实现页面元素的高效更新

image-20191215170027772
<body>

    <div id="app">
    	<ρ class="item">节点1p>
    div>

	<script>
        createElement(){
      
            return {
      
                tag: 'div',
                data: {
      id:app},
                children: [
                    {
      
                        tag:'p',
                        data: {
      
                            class: item
                        },
                        children: ['节点1']
                    }
                ]
        	}
        }
    script>
body>

Diff算法

Diff算法的作用是用来计算出 Virtual DOM 中被改变的部分,然后针对该部分进行原生DOM操作,而不用重新渲染整个页面。

Diff算法在React中处于主导地位,是React Virtual DOM和渲染的性能保证,这也是React最有魅力、最吸引人的地方。

React 将 Virtual DOM 树转换为 actual DOM 树的最小操作的过程称为调和, diff 算法便是调和的结果,React 通过制定大胆的策略,将 O(n3)的时间复杂度转换成 O(n)。

下面是 React diff 算法的 3 个策略:

  • 策略一:Web UI 中 DOM 节点跨层级的移动操作特别少。可以忽略不计。
  • 策略二:拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件将会生成不同的树形结构。
  • 策略三:对于同一层级的一组子节点,它们可以通过唯一 id 进行区分。

基于以上三个策略,React 分别对 tree diff、component diff 以及 element diff 进行算法优化。

基础语法

React.Component

React 的组件可以定义为 class 或函数的形式。class 组件目前提供了更多的功能。如需定义 class 组件,需要继承 React.Component

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

React.Component 的子类中有个必须定义的 render() 函数。

ReactDOM.render

ReactDOM.render()方法是React框架中最基础的方法,这个方法的作用是将模板转化为HTML的语法,然后插入到指定的DOM节点中。其目的就是将虚拟DOM渲染成真实的DOM

ReactDOM.render(
    <h1>Hello, world!</h1>,
    document.getElementById('root')
);

上面的代码将一个

插入到root的节点中,其中document.getElementById('root')指定被插入的节点。

pic_001

同理,这是一个动态渲染的例子

function tick() {
     
    const element = (
        <div>
            <h1>Hello, world!</h1>
            <h2>It is {
     new Date().toLocaleTimeString()}.</h2> 
			//toLocaleTimeString() 方法可根据本地时间把 Date 对象的时间部分转换为字符串,并返回结果。
        </div>
      );
    ReactDOM.render(
        element,
        document.getElementById( 'root' )
    );
}
//setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。
setInterval( tick, 1000 );
pic_001

4. 完成一个简单的demo——TodoList

通过React框架,完成TodoList功能

前期:完善功能

  1. 构造函数,存放数据
  // 构造函数
  constructor(props) {
     
    super(props);
    this.state = {
     
      list: ["learn react", "learn English"],
      inputValue: ""
    };
  }
  1. 通过render函数将数据渲染到页面上
  // 将数据渲染到页面
  render() {
     
    return (
      <div>
        <div>
          <input value={
     this.state.inputValue} onChange={
     this.handleInputChange.bind(this)}/>
          {
     /* bind(this) 可将 handleBtnClick()中的this与外部this绑定*/}
          <button onClick={
     this.handleBtnClick.bind(this)}>add</button>
        </div>
        <ul>
          {
     /* map()函数用于对数组做循环 
              每一个key值都是不同的,没有key值会报警告,可将数组中对应的下标当做key值*/}
          {
     this.state.list.map((item, index) => {
     
            return <li key={
     index} onClick={
     this.handleItemClick.bind(this,index)}>{
     item}</li>;
          })}
        </ul>
      </div>
    );
  }

效果图:

image-20191216202346132
  1. add按钮添加绑定事件,获取输入框数据,点击按钮后将输入框内容添加到列表中
  // 添加按钮函数
  handleBtnClick() {
     
    // 点击按钮时改变state中list的数据
    this.setState({
     
      // '...':展开运算符,等价于list中原本包含的内容
      list: [...this.state.list, this.state.inputValue],
      inputValue: ""
    });
  }
  // 获取输入框数据函数
  handleInputChange(e) {
     
    this.setState({
     
      inputValue: e.target.value
    });
  }

效果图:

Animation 5
  1. 删除功能:点击删除对应的代办事项
  // 删除列表项目
  handleItemClick(index){
     
    const list = [...this.state.list];
    // splice()从数组中添加/删除对应下标项目
    list.splice(index,1);
    this.setState({
         //等价于this.setState({list})
      list: list
    })
  }

效果图:

Animation 6

中期:组件拆分

目前,页面时一整个TodoList组件,不利于后期的维护与运行效率,所以需要把其拆分成更小的组件,将代办事项抽离出来变成子组件,可以使得整体结构更清晰,便于理解。

  1. 新建一个TodoItem.js文件,在其中定义一个列表项组件当作子组件
  2. 在父组件TodoList.js中引入定义好的子组件,实现拆分
  3. 父子组件互相传值,接收参数,实现功能

TodoItem.js:

// 子组件
// 子组件通过props的形式接收父组件传递来的参数
// 子组件向父组件传值,要调用父组件传递过来的方法
import React from 'react';
export default class TodoItem extends React.Component{
     
    constructor(props){
     
        super(props);
        this.handleDelete = this.handleDelete.bind(this)
    }
    // 删除代办事项 | 子组件向父组件传值
    handleDelete(index){
     
        this.props.delete(this.props.index)
    }
    render() {
     
        const {
     content} = this.props;
        return(
            <li onClick={
     this.handleDelete}>{
     content}</li>
        )
    }
}

TodoList.js:

import TodoItem from './TodoItem';
    handleDelete(index){
     
        console.log(index)
        const list = [...this.state.list];
        // splice()从数组中添加/删除对应下标项目
        list.splice(index,1);
        this.setState({
         //等价于this.setState({list})
            list: list
        })
    }
...
return <TodoItem />

后期代码优化,调整样式

  1. 通过提前声明的方式,减少代码冗余,美化代码结构,使代码便于阅读与理解
  2. 将实现功能的代码单拎出来,封装成函数,在结构中进行调用,清晰直观。

TodoList.js完整代码

// 父组件
// 父组件通过属性的方式向子组件传递参数(eg:content)
// 进行代码优化
import React from "react";
import TodoItem from './TodoItem';
export default class Todolist extends React.Component {
     
  // 构造函数
  constructor(props) {
     
    super(props);
    this.state = {
     
      list: ["learn react", "learn English"],
      inputValue: ""
    };
  	//提前声明this指向
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleBtnClick = this.handleBtnClick.bind(this);
    this.handleDelete = this.handleDelete.bind(this);
  }
  // 添加按钮函数
  handleBtnClick() {
     
    // 点击按钮时改变state中list的数据
    this.setState({
     
      // '...':展开运算符,等价于list中原本包含的内容
      list: [...this.state.list, this.state.inputValue],
      inputValue: ""
    });
  }
  // 获取输入框数据函数
  handleInputChange(e) {
     
    this.setState({
     
      inputValue: e.target.value
    });
  }
  // 同上
  handleDelete(index){
     
    console.log(index)
    const list = [...this.state.list];
    // splice()从数组中添加/删除对应下标项目
    list.splice(index,1);
    this.setState({
         //等价于this.setState({list})
      list: list
    })
  }
  // 
  getTodoItems(){
     
    return(
      // map()函数用于对list数组中的item做循环 
      // 每一个key值都是不同的,没有key值会报警告,可将数组中对应的下标当做key值
      this.state.list.map((item, index) => {
     
        return (
          <TodoItem 
            delete={
     this.handleDelete} 
            key={
     index} 
            content={
     item} 
            index={
     index} />
          )
        {
     /* return 
  • {item}
  • ; */
    } }) ) } // 将数据渲染到页面 render() { //定义组件的类里面要有一个render的函数 // jsx语法 return ( //return出去的语句,决定了此组件在页面显示的内容 // 组件要放在一个大的闭合标签内,下面的this指向该组件 <div> <div> <input value={ this.state.inputValue} onChange={ this.handleInputChange}/> { /* bind(this) 可将 handleBtnClick()中的this与外部this绑定*/} <button onClick={ this.handleBtnClick}>add</button> </div> <ul> { this.getTodoItems()} </ul> </div> ); } }
    1. 增加css样式,美化样式

    效果图:

    Animation 7

    5. React衍生产物

    React Native

    React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的JS框架 React 在原生移动应用平台的衍生产物,支持iOS和安卓两大平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可以进入移动应用开发领域。

    React Native主要特性如下:

    • 原生的iOS组件
      React Native主张“Learn once, write everywhere”而非其他跨平台工具一直宣扬的“Write once, run everywhere”。通过React Native,开发者可以使用UITabBar、UINavigationController等标准的iOS平台组件,让应用界面在其他平台上亦能保持始终如一的外观、风格。
    • 异步执行
      JavaScript应用代码和原生平台之间所有的操作都采用异步执行模式,原生模块使用额外线程,开发者可以解码主线程图像、后台保存至磁盘、无须顾忌UI等诸多因素直接度量文本设计布局。

    • 触摸处理
      React Native引入了一个类似于iOS上Responder Chain响应链事件处理机制的响应体系,并基于此为开发者提供了诸如TouchableHighlight等更高级的组件。

    React VS React Native:

    React学习(一)——初步了解,完成ToDoList功能demo_第1张图片

    React VR

    React VR旨在允许Web开发人员使用React的声明方法(特别是React Native)来创作虚拟现实(VR)应用程序。

    React VR使用Three.js 来支持较低级别的WebVR 和 WebGL API. WebVR是用于访问Web上VR设备的API。 WebGL(Web图形库)是一种无需使用插件即可用于在任何兼容的Web浏览器中渲染3D图形的API。

    React VR类似于React Native,因为它使用ViewImageText作为核心组件,并且支持Flexbox布局。 此外,React VR还将PanoMeshPointLight等VR组件添加相关库中。

    可以创建一个简单的项目来查看VR效果,下面是命令行代码

    效果图:

    React Fiber

    React 16 之后的版本,v对底层核心算法进行了改良。官方的一句话解释是“React Fiber是对核心算法的一次重新实现”

    在现有React中,更新过程是同步的,这可能会导致性能问题。当组件树过于庞大时,又同时进行很多事情,将造成界面卡顿,形成很不好的用户体验。

    React Fiber把更新过程碎片化,执行过程如下面的图所示,每执行完一段更新过程,就把控制权交还给React负责任务协调的模块,看看有没有其他紧急任务要做,如果没有就继续去更新,如果有紧急任务,那就去做紧急任务。维护每一个分片的数据结构,就是Fiber,其最大的使命是解决大型React项目的性能问题

    6. 个人小结

    React学习(一)——初步了解,完成ToDoList功能demo_第2张图片
    通过一个星期对React的学习,我知道了什么是ReactReact用来做什么,React被开发出来的意义,以及通过简单上手使用React框架,完成基础的demo——TodoList。我认为,在学习React框架时,最重要的是理解它的核心概念,React的本质是用JS对象来模拟DOM即创建虚拟DOM,通过虚拟DOM与真实DOM进行对比,实现页面的按需更新。区别于传统数据渲染(提交整个页面的DOM元素,全部刷新),通过React我们可以将结构变化的部分更新到真实DOM中,进行局部更新,极大的提高了效率。React的核心思想是组件化,HTML、CSS、JS合为一体。一切皆是Component,所有页面都可以拆分成组件,结构清晰直观。React是一个UI库,描述页面标签如何展示,它可以与已知的库或框架很好地配合,这也提现了它独特的灵活性。它还有很多优点,需要继续去挖掘。
    协调的模块,看看有没有其他紧急任务要做,如果没有就继续去更新,如果有紧急任务,那就去做紧急任务。维护每一个分片的数据结构,就是Fiber,其最大的使命是解决大型React项目的性能问题

    你可能感兴趣的:(前端,react)