react基础知识1

1. react概述

1.1 react介绍

react 用于构建用户界面的 JavaScript 库 。

React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MV* 框架,都不满意,就决定自己写一套,用来架设 Instagram 照片墙 的网站(17年 用户量7亿+)。做出来以后,发现这套东西很好用,就在2013年5月开源了。

1.2 react文档

[英文文档](https://reactjs.org/)

[中文文档](https://doc.react-china.org/)

[github地址](https://github.com/facebook/react)

1.3 react特点

  • 声明式:React 可以非常轻松地创建用户交互界面。为你应用的每一个状态设计简洁的视图,在数据改变时 React 也可以高效地更新渲染界面。

  • 组件化:创建好拥有各自状态的组件,再由组件构成更加复杂的界面。

  • 一次学习,随处编写:无论你现在正在使用什么技术栈,你都可以随时引入 React 开发新特性。React 也可以用作开发原生应用的框架 React Native.

1.4 react的优势

  • 使用组件化开发方式,符合现代Web开发的趋势

  • 技术成熟,社区完善,配件齐全,适用于大型Web项目(生态系统健全)

  • 由Facebook专门的团队维护,技术支持可靠

  • ReactNative - Learn once, write anywhere: Build mobile apps with React

  • 使用方式简单,性能非常高,支持服务端渲染 SSR

2. react初体验

2.1 引包(安装)

cdn的方式




本地的方式






2.2 创建react元素

注意,如果在浏览器端使用babel,必须指定type='text/babel'

2.3 渲染元素到页面

准备html的结构

把元素渲染到页面

// 把元素渲染到页面中
// 参数1:需要渲染的react对象
// 参数2:指定渲染到页面中的容器
ReactDOM.render(
    element,
    document.getElementById('app')
)

2.4 createElement方法解释

[api地址](https://react.docschina.org/docs/react-api.html#createelement)

/*
作用:根据指定的参数,创建react对象
参数1:指定创建虚拟DOM的类型
  类型:string 或者 react组件
	1. 任意字符串类型的标签名称,比如:'div' / 'span'
	2 react组件类型,比如:
参数2:指定元素自身的属性
	类型:对象或者null
参数3:当前元素的子元素
	类型:string 获取react对象
返回值:react对象
*/
React.createElement(
  type,
  [props],
  [...children]
)

2.5 render方法解释

[api地址](https://react.docschina.org/docs/react-dom.html#render)

/* 
  功能:渲染一个React元素,添加到位于提供的container里的DOM元素中
  参数1::指定要渲染的react对象
  参数2:指定渲染到页面中的容器(DOM对象)
  参数3:回调函数
*/
ReactDOM.render(
  element,
  document.getElementById('app')
)

总结:使用createElement创建react对象非常的麻烦,推荐您使用JSX

2.6 小练习

  • 苹果
  • 香蕉
  • 橘子
// 创建一个react对象
    let li1 = React.createElement('li', null, '苹果')
    let li2 = React.createElement('li', null, '香蕉')
    let li3 = React.createElement('li', null, '橘子')
    let ul = React.createElement('ul', {id: 'list'}, li1, li2, li3)

// 把react对象渲染到页面
    ReactDOM.render(ul, document.getElementById('app'))

3. jsx语法

3.1 jsx快速体验

// 通过jsx语法创建react对象
const element = 
你好啊
// 渲染react对象 ReactDOM.render( element, document.getElementById('app') )

3.2 jsx讲解

jsx: 一种 JavaScript 的语法扩展。 在react中推荐使用react来描述用户界面(创建react对象)

通过jsx创建react对象,实质内部还是调用createElement方法,只不过jsx语法更加的简洁

  • jsx虽然看起来像模板,但是jsx是一个js对象,并不是字符串,也不是DOM对象

  • 在jsx中可以使用表达式, 只需要使用{}包裹起来即可

  • 为了代码可读性,书写jsx的时候需要保证代码的缩进,并且给jsx的代码使用()包裹起来

  • jsx中的元素只能有一个根元素,并且标签必须闭合。

  • 因为 JSX 的特性更接近 JavaScript 而不是 HTML ,所以jsx的属性是js的属性,比如class变成了className

4. react的虚拟DOM与diff算法

React 中最值得称道的部分莫过于 Virtual DOM 与 diff 的完美结合,特别是其高效的 diff 算法,让用户可以无需顾忌性能问题而”任性自由”的刷新页面 。

4.1 虚拟DOM

虚拟DOM(Virtual DOM):虚拟DOM就是使用javascript的对象来描述了DOM结构 。

  • 为什么要有虚拟DOM?

    • 因为操作真实DOM的代价是非常昂贵的,随便一个DOM对象,都有很多很多的属性

    • DOM中大部分的属性都不是我们需要关注的

  • 虚拟DOM:

    • 使用js对象来描述一个DOM结构,在react框架中,描述一个DOM的对象,使用的一个虚拟DOM

    • 页面的更新可以先全部反映在js对象上,操作内存中的js对象的速度显然要快多了,不需要重绘与回流

    • 等更新完后,再将最终的js对象映射成真实的DOM,交由浏览器去绘制。

4.2 DIFF算法

react中通过diff算法来决定如何更新视图中的内容

[官方文档-diff]([diff算法 - 中文文档](https://www.reactjscn.com/docs/reconciliation.html))

diif算法的举例

如果两棵树的根元素类型不同,React会销毁旧树,创建新树:

// 旧树
张三
// 新树 张三

对于类型相同的React DOM 元素,如果仅仅是属性不同,只更新不同的属性 :

// 旧
// 新
只更新:className 属性 // 旧
// 新
只更新:color属性

添加节点的情况 :

// 旧
  • first
  • second
// 新
  • first
  • second
  • third
// 在虚拟DOM中添加
  • third
  • // 效率不高 // 旧
    • a
    • b
    // 新
    • c
    • a
    • b
    // React将改变每一个子节点, 不会保证
  • a
  • b
  • 不变化

    带key的情况: 

    // 旧
    
    • a
    • b
    // 新
    • c
    • a
    • b
    // react会根据唯一的key来移动元素 // 在遍历数据时,推荐在使用 key 属性

    react中DOM的更新方式

    1. 使用虚拟DOM(JavaScript)对象结构表示 DOM 树的结构,根据虚拟DOM渲染出真正的DOM树

    2. 当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异(diff算法)

    3. 把2所记录的差异应用到步骤1所构建的真正的DOM树上,视图就更新了

    参考资料

    [虚拟DOM介绍](https://www.jianshu.com/p/616999666920)

    [如何实现一个 Virtual DOM 算法](https://github.com/livoras/blog/issues/13)

    5. 函数组件与类组件

    函数组件:

    function Hello(props) {
          return (
            

    大家好

    {props.name} ---- {props.age}

    ) } ReactDOM.render( , document.getElementById('app') )

    // 定义组件 函数组件

    // 1. 定义的组件名必须首字母大写,为了和html标签区分开

    // 2. 必须返回一个jsx

    // 组件传值:

    // 组件中怎么接受到传递过来的值, 通过props参数来接收即可

    // props是只读的, 在组件接收到的内容不允许修改

    // 函数组件: 有一个缺点, 没有状态 函数组件自己没有数据

    // 函数组件中的数据都是 父组件传递过来的数据, 组件无法修改

    类组件:

    class Hello extends React.Component {
          // 在类组件中想要获取传递过来的值,也是通过props来获取
          constructor(props) {
            // 表示把props添加给了当前组件, 将来在任意的函数中,都可以通过this.props来访问到
            super(props)
          }
    
          render() {
            return (
              
    大家好 --{this.props.name} ----{this.props.age}
    ) } } // 怎么给类组件传值 ReactDOM.render( , document.getElementById('app') )

    计时器案例(使用函数组件和类组件完成)

     function Clock (props) {
          return (
            

    北京时间

    当前时间:{props.date.toLocaleString()}

    ) } setInterval(() => { // 如何渲染的Clock组件 ReactDOM.render( , document.getElementById('app') ) }, 1000)
        // 定义一个clock组件
        class Clock extends React.Component {
          constructor(props) {
            super(props)
    
            this.state = {
              date: new Date(),
              name: 'zs'
            }
          }
          render() {
            return (
              

    北京时间

    当前时间:{this.state.date.toLocaleString()}

    大家好,我的名字是{this.state.name}

    ) } // DOM结构渲染好了, 开启一个定时器,动态的修改时间 componentDidMount() { this.timeId = setInterval( () => { // 修改状态, 在react中,修改状态不能直接通过this.state.xxx来修改 // 必须通过this.setState()来进行修改 // this.state.date = new Date() // this.state.name = '李四' // // 同步 // this.setState(this.state) // 原因:react框架和小程序 不是双向数据绑定的 // vue和angular都是双向数据绑定 this.setState({ date: new Date(), name: 'ls' }) }, 1000) } // 关闭定时器 componentWillUnmount () { clearInterval(this.timeId) } } ReactDOM.render( , document.getElementById('app') )

    6. 生命周期函数

    https://www.jianshu.com/p/514fe21b9914

    React v16.0前的生命周期

                                          react基础知识1_第1张图片

    react基础知识1_第2张图片

    旧版生命周期如果要开启async rendering,在render函数之前的所有函数,都有可能被执行多次。

    getDerivedStateFromProps:

    getDerivedStateFromProps无论是Mounting还是Updating,也无论是因为什么引起的Updating,全部都会被调用。

    getSnapshotBeforeUpdate:

    getSnapshotBeforeUpdate()被调用于render之后,可以读取但无法使用DOM的时候。它使您的组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置)。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。

    官网例子:

    class ScrollingList extends React.Component {
      constructor(props) {
        super(props);
        this.listRef = React.createRef();
      }
    
      getSnapshotBeforeUpdate(prevProps, prevState) {
        //我们是否要添加新的 items 到列表?
        // 捕捉滚动位置,以便我们可以稍后调整滚动.
        if (prevProps.list.length < this.props.list.length) {
          const list = this.listRef.current;
          return list.scrollHeight - list.scrollTop;
        }
        return null;
      }
    
      componentDidUpdate(prevProps, prevState, snapshot) {
        //如果我们有snapshot值, 我们已经添加了 新的items.
        // 调整滚动以至于这些新的items 不会将旧items推出视图。
        // (这边的snapshot是 getSnapshotBeforeUpdate方法的返回值)
        if (snapshot !== null) {
          const list = this.listRef.current;
          list.scrollTop = list.scrollHeight - snapshot;
        }
      }
    
      render() {
        return (
          
    {/* ...contents... */}
    ); } }

     

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