react学习笔记基础篇(1)

87 阅读6分钟

一、React核心概念一、 React核心概念

虚拟DOM

在JS中,通过操作JS中的DOM对象来完成对页面的重排或重绘。但是DOM的操作成本是比较高的,所以引入虚拟DOM的概念。

虚拟DOM\color{red}虚拟DOM是对真实DOM的映射,React通过新旧虚拟DOM对比,得到需要更新的部分,实现数据的增量更新。

diff算法

当我们修改数据时,只希望更新我们修改的那一小块dom,而不是整个dom,diff算法就帮我们实现了这点。

diff算法的本质:找出两个对象之间的差异,目的是尽可能做到节点复用

diff策略:用三大策略,将O(n3)f复杂度转化为O(n)复杂度 1.策略一:针对树结构(tree diff),对UI层的DOM节点跨层级的操作进行忽略。(数量少)

特点:

  • React通过使用updateDepth对虚拟Dom树进行层次遍历
  • 两棵树只对同一层级节点进行比较,只要该节点不存在了,那么该节点与其所有子节点会被完全删除,不再进行进一步比较
  • 只要遍历一次,便完成对整个DOM树的比较 2.策略二:针对组件结构(component),拥有相同类的两个组件生成相似的树形结构,拥有不同类的两个组件会生成不同的属性结构。 3.策略三:针对元素结构(element-diff),对于同一层级的一组节点,提供了三种节点操作:插入,移动,删除,使用具有唯一性的id区分 特点:
  • 插入:新的组件不在原来的集合中,而是全新的节点,则对集合进行插入操作
  • 删除:组件已经在集合中,但集合已经更新,此时节点就需要删除
  • 移动:组件已经存在于集合中,并且集合更新时,组件并没有发生更新,只是位置发生改变

组件化

每个组件都符合开放-封闭原则,封闭是针对渲染工作流来说的,指的是组件内部的状态都由自身维护,只处理内部的渲染逻辑。开放是针对组件通信来说的,指的是不同组件可以通过props(单项数据流)进行数据交互

二、JSX的使用二、JSX的使用

JSX也是一个表达式,是对JavaScript的语法扩展,在编译之后,JSX表达式会被转为普通javascript函数调用,并且对其取值后得到JavaScript对象。

JSX 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖。

语法规则

  • 定义虚拟DOM时,不要写引号
  • 标签中混入JS表达式时要用 {}
  • 样式的类名指定不用 class,要用className
  • 内联样式,要用style = {{key: value}} 的形式去写
  • 只有一个根标签
  • 标签必须闭合
  • 标签首字母

(1)若小写字母开头,则将该标签转为 html同名元素,若html中无该标签,则报错

 (2)若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错

三、React生命周期

生命周期指的是组件实例从创建到销毁的过程,函数组件没有生命周期,只有类组件才有,因为只有class组件会创建组件实例

组件的生命周期分为挂载、更新、卸载阶段

挂载

由ReactDOM.render()触发 ---------------初次渲染

  1. constructor()
  2. getDerivedStateFromProps
  3. render()
  4. componentDidMount() ------------ 常用

更新

由组件内部this.setState()或父组件重新render触发

  1. getDerivedStateFromProps
  2. shouldComponentUpdate()
  3. render()
  4. getSnapshotBeforeUpdate()
  5. componentDidUpdate()

卸载

由ReactDOM.unmountComponentAtNode()触发

  1. componentWilUnmount() ----------- 常用

一般在这做一些收尾的事,例如:关闭定时器、取消订阅消息

222.png

四、组件和props

组件类似于函数,它接受任意的入参,并返回用于描述页面展示内容的React元素

构造函数方式

  • 组件如果需要接收外界的数据,需要在构造函数列表中使用props来接收,props就相当于DOM元素的属性一般赋值。
  • 在一个组件中,必须要一个返回值,这个返回值是一个合法的JSX虚拟DOM元素,如果return null,则表示此组件是空的
  • props是只读的,props需要用形参接收
  • 组件的首字母必须大写
// 函数组件
function Welcome(props) {
    return <h1>Helllo,{props.name}<h1>
}

class方式

  • 使用class定义组件,必须让组件继承自React.Component
  • 组件内部必须有render函数,render函数必须返回合法的JSX虚拟DOM结构
  • 最基本的组件结构:
  • props是只读的,在class中可以通过this.props使用
  • 有自己的私有数据state,class内部自身维护的可读写的数据,不通于props是通过外界传递而来
// class 组件
function SayHello extends React.Component{
    constructor(props) {
        super(props);
        this.state = {message: 'Hello'};
        this.handleClick = this.handleClick.bind(this);
    }
    handleClick() {
        alert(this.state.message);
    }
    render() {
        return(
            <button onClick={this.handleClick}>
                say hello
            </button>
        )
    }
}

所有的组件都必须像纯函数一样保护它们的props不被更改 组件遵循单一功能原则,并且是单向数据传递

五、Redux工作原理

Redux是一个状态管理库,使用场景:

  • 跨层级组件数据共享与通信
  • 一些需要持久化的全局数据,比如用户登录信息

333.png

  • state:驱动应用的真实数据源头
  • view:基于当前状态的视图声明性描述
  • actions:根据用户输入在应用程序中发生的事件,并触发状态更新

六、React-router

页面路由

  window.location.href = '地址' // www.baidu.com
  history.back()  //回退

hash路由

import {HashRouter as Router,Route,Link} from 'react-router-dom'
class A extends React.Comopnent{
    constructor(props) {
        super(props)
    }
    render() {
        return (
            <div>A</div>
        )
    }
}

class B extends React.Comopnent{
    constructor(props) {
        super(props)
    }
    render() {
        return (
            <div>B</div>
        )
    }
}
class Wrapper extends React.Component{
    constructor(props){
        super(props)
    }
    render() {
        return (
            <div>
                <Link to="/a">组件A</Link>
                <br />
                <Link to="/b">组件B</Link>
                {this.props.children}
            </div>
        )
    }
}
ReactDOM.render(
    <Router>
        <Wrapper>
            <Route path="/a" component={A}></Route>
            <Route path="/b" component={B}></Route>
        </Wrapper>
    </Router>
)

h5路由

history.pushState('name', 'title', '/path')  // 推进一个状态
history.replaceState('name', 'title', '/path') // 更换一个状态
window.onpopstate = function () {
    console.log(window.location.href)
    console.log(window.location.pathname)
    console.log(window.location.hash)
    console.log(window.location.search)
}

react-router引入

import {BrowserRouter as Router,Route,Link} from 'react-router-dom'

router传参,组件接受不同组件传参

引入switch

七、Hook

Hook是React16.8的新增特性,它可以在不编写class的情况下使用state以及其他React特性

stateHook

import React,{useState} from 'react'
function Example() {
    // 声明一个叫做“count”的state变量
    const [count,setCount] = useState(0);
    return (
        <div>
            <p>You Click {count} times</p>
            <button onClick={() => setCount(count + 1)}>
                Click
            </button>
        </div>
    )
}

在这里,useState就是一个Hook,通过在函数组件里调用它来给组件添加一些内部的state。React会在重复渲染时保留这个state

Hook是一个特殊的函数,可以“钩入”React的特性

useState是允许在React函数组件中添加state的Hook 我们声明了一个叫count的state变量,然后把它设为0。React会在重复渲染时记住它当前的值,并且提供最新的值给我们的函数,我们可以通过调用setCount来更新当前的count

  1. 读取state this.state.count
  2. 更新state 调用this.setState()

Effect Hook

Effect Hook可以在函数组件中执行副作用操作。 数据获取,设置订阅以及手动更改React组件中的DOM都属于副作用

import React,{ useState,useEffect} from 'react';
function Example() {
    const [count, setCount] = useState(0);
    useEffect(() => {
        document.title = `You Click ${count} times`;
    })
    return(
        <div>You Clicked {count}</div>
    )
}

useEffect做了什么,通过使用这个Hook,你可以告诉React组件需要在渲染之后执行某些操作。React会保存你传递的函数,并且在执行DOM更新之后调用它。 默认情况下,useEffect在第一次渲染之后和每次更新之后都会执行

自定义Hook

自定义Hook是一个函数,其名称以“use”开头,函数内部可以使用其他的Hook