React

React 16

super

在ES6中,在子类的 constructor 中必须先调用 super 才能引用 this

setState (partialState, callback )

有两个参数

  • 对象键值对
  • 函数:可以获取最新值

在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout 中都是同步的。

setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数拿到更新后的结果。

setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新。

问题:调用 setState 之后发生了什么

  • setState 的时候,React 会为当前节点创建一个 updateQueue 的更新列队。
  • 然后会触发 reconciliation 过程,在这个过程中,会使用名为 Fiber 的调度算法,开始生成新的 Fiber 树, Fiber 算法的最大特点是可以做到异步可中断的执行。
  • 然后 React Scheduler 会根据优先级高低,先执行优先级高的节点,具体是执行 doWork 方法。
  • doWork 方法中,React 会执行一遍 updateQueue 中的方法,以获得新的节点。然后对比新旧节点,为老节点打上 更新、插入、替换 等 Tag。
  • 当前节点 doWork 完成后,会执行 performUnitOfWork 方法获得新节点,然后再重复上面的过程。
  • 当所有节点都 doWork 完成后,会触发 commitRoot 方法,React 进入 commit 阶段。
  • 在 commit 阶段中,React 会根据前面为各个节点打的 Tag,一次性更新整个 dom 元素。
refs

Refs 是 React 提供给我们的安全访问 DOM 元素或者某个组件实例的句柄。例:

<form onSubmit={this.handleSubmit}>
    <input type='text' ref={(input) => this.input = input} />
</form>
// this.input.value  访问 
react-router
  • 二级路由

    在一级路由内嵌套

  • 路由匹配和重定向

    // SWitch 包裹,例 
    <Switch>
        {/* 重定向 */} 
    	<Redirect from="/" to="/home" exact></Redirect>
         {/*如果都没匹配到,则跳转到下面的  */} 
    	<Route component={Error}></Route>
    </Switch>
    
  • 路由传参和动态路由

    // 传入一个动态路由/:id 
     <Route path="/shopcar/:id" component={ Shopcar } />   
    // to属性增加pathname和search 
    <Link to={{pathname: '/shopcar/001',search: '?a=1&b=2',}}></Link>
    
  • 路由组件守卫

    使用高阶组件的形式,将路由组件放在高阶组件返回,通过判断逻辑返回相应的组件

    每个路由都有EnterLeave钩子,用户进入或离开该路由时触发。

  • Route渲染方式 优先级: children > component > render

    • children

      // 无论 location 是否匹配,都会渲染
      <Route 
          path='/a' 
          children={({ match }) => (
              <Link to='/a'> hello world </Link>
          )}
      />
      
    • render

      // 避免重复的无必要的加载,匹配时渲染
      <Route
          path="/home"
          render={() => {
              return <div> home </div>
          }}
       />
      
    • component

      // 只有 path 匹配时,组件才呈现。
      <Route path="/user" component={ component } />
      
  • withRouter

    将一个组件包裹进Route里面, 然后react-router的三个对象history, location, match就会被放进这个组件的props属性中

生命周期

15和16版本的区别

image-20201121091647026

  • 挂载

    • componentWillMount()

      在挂载之前被调用

    • constructor()

      组件挂载之前,会调用它的构造函数
      应在其他语句之前前调用 super(props) ,否则无法访问 this

    • static getDerivedStateFromProps(props, state)

      会在调用 render 方法之前调用,并且在初始挂载及后续更新时(挂载时,接收到新的props,调用了setState和forceUpdate)都会被调用

      应返回一个对象来更新 state,如果返回 null 则不更新任何内容。

    • render()

      render() 方法是 class 组件中唯一必须实现的方法。
      当 render 被调用时,它会检查 this.propsthis.state 的变化

    • componentDidMount()

      在组件挂载后(插入 DOM 树中)立即调用,可以进行实例化请求

  • 更新

    • static getDerivedStateFromProps(props, state)

    • componentWillReceiveProps(nextProps)

      已挂载的组件接收新的 props 之前被调用

      父组件导致组件重新渲染,即使 props 没有更改,也会触发此方法

    • shouldComponentUpdate(nextProps, nextState)

      propsstate 发生变化时,会在渲染之前调用,默认返回 true ,如果返回 false ,则会跳过更新
      可以将 this.statenextState , this.propsnextProps 比较
      此处可以通过返回 truefalse 进行性能优化

    • render()

    • getSnapshotBeforeUpdate(prevProps, prevState)

      在最近一次渲染输出(提交到 DOM 节点)之前调用

      任何返回值将作为参数传递给 componentDidUpdate()

    • componentWillUpdate( nextProps, nextState )

      会在渲染之前调用

    • componentDidUpdate(prevProps, prevState, snapshot)

      在更新后会被立即调用,首次渲染不会执行此方法。

  • 卸载

    • componentWillUnmount()

      会在组件卸载及销毁之前直接调用

  • 错误处理

    • static getDerivedStateFromError(error)

      在后代组件抛出错误后被调用。 它将抛出的错误作为参数,并返回一个值以更新 state

    • componentDidCatch(error, info)

      此生命周期在后代组件抛出错误后被调用

高阶组件(HOC)

高阶组件是一个函数,接收一个组件作为参数,并返回一个组件,例如 connectwithRouter

返回一个组件,通常是第一个参数,携带着需要的数据返回

如何在Hook中使用HOC ?

使用 Hook 提供的 useState , useEffect 提供的代替方法,代替 class 组件中的 setState、生命周期

使用场景:

  • 人员权限访问页面
  • 不同类别的列表
suspense 组件

Suspense 让组件“等待”某个异步操作,直到该异步操作结束即可渲染

组件通信
  • 父子组件:通过props传递给子组件,子组件通过props接收;子组件通过父组件传递的函数传参给父组件。
  • 跨组件通信
  • 非嵌套组件
    • 发布订阅模式
    • Redux、Mobx
无状态组件和有状态组件

无状态组件:使用函数直接创建组件,使用方便,易于书写。应避免使用this

有状态组件:通过class创建组件,有生命周期,可以通过this接收状态和属性

属性(props)和状态(state)

组件不可修改属性,但可以修改自己的状态

更新 state 和 props 会触发哪些状态

// 更改state : 
// getDerviedStateFromProps
// shouldComponentUpdate
// render
// getSnapshotBeforeUpdate
// componentDidUpdate


// 更改props
// getDerviedStateFromProps
// shouldComponentUpdate
// render
// getSnapshotBeforeUpdate
// componentDidUpdate

// 所触发的生命周期是相同的,但两者的区别是更改props时,生命周期的props和state都是有值的,更改state时,生命周期的第一个参数,也就是 props 值是空的
受控组件和非受控组件

使用setState进行更新状态的称为受控组件

使用refs获取的称为非受控组件

大白话说就是需不需要干涉,不干涉的是非受控组件,干涉的是受控组件

对于表单组件的封装,无论class组件还是针对于类组件,都需要进行表单回显

context
  • 第一种写法 (低版本)

    //App.js
    import React from 'react';
    import Son from './son';//引入子组件
    // 创建一个 theme Context,
    export const { Provider, Consumer } = React.createContext("默认名称");
    export default class App extends React.Component {
      render() {
        let name = "小人头"
        return (
          //Provider共享容器 接收一个name属性
          <Provider value={name}>
            <p>父组件定义的值:{name}</p>
            <Son />
          </Provider>
        );
      }
    }
    
    //son.js 子类
    import React from 'react';
    import { Consumer } from "./App";//引入父组件的Consumer容器
    import Grandson from "./grandson.js";//引入子组件
    function Son(props) {
      return (
        //Consumer容器,可以拿到上文传递下来的name属性,并可以展示对应的值
        <Consumer>
          {(name) =>
            <div>
              <p>子组件。获取父组件的值:{name}</p>
              {/* 孙组件内容 */}
              <Grandson />
            </div>
          }
        </Consumer>
      );
    }
    export default Son;
    
    //grandson.js 孙类
    import React from 'react';
    import { Consumer } from "./App";//引入父组件的Consumer容器
    function Grandson(props) {
      return (
        //Consumer容器,可以拿到上文传递下来的name属性,并可以展示对应的值
        <Consumer>
          { (name) => <p>孙组件。获取传递下来的值:{name}</p>}
        </Consumer>
      );
    }
    export default Grandson;
    
  • 第二种写法

    // 新建global.js
    import React from 'react'
    export const ThemeContext = React.createContext('light');
    
    //App.js
    import React from 'react';
    import Toolbar from './toolbar';//引入子组件
    import { ThemeContext } from './global'
    class App extends React.Component {
      render() {
        return (
          <ThemeContext.Provider value="dark">
            <Toolbar />
          </ThemeContext.Provider>
        );
      }
    }
    
    export default App
    
    // Toolbar.js
    import  ThemedButton from './ThemedButton'
    function Toolbar() {
      return (
        <div>
          <ThemedButton />
        </div>
      );
    }
    export default Toolbar
    
    //ThemedButton.js
    import React from 'react'
    import { ThemeContext } from './global'
    
    class ThemedButton extends React.Component {
      static contextType = ThemeContext;
      render() {
        return <p>{this.context}</p>;
      }
    }
    export default ThemedButton
    
类组件中的优化
React.memo
  • React.memo 为高阶组件,仅可在函数组件使用
  • 仅检查 props 变更,当context变化时仍然会重新渲染
  • 默认情况下其只会对复杂对象做浅层对比,如果想要控制对比过程,通过第二个参数传入来实现
  • shouldComponentUpdate()返回值相反
PureComponent
  • React.PureComponent 中以浅层对比 prop 和 state,和React.component类似,仅在类组件使用
项目配置less
  1. webpack.config.js

    // 1 . 
    const lessRegex = /\.less$/;
    const lessModuleRegex = /\.module\.less$/;
    
    // 2 .getStyleLoaders 函数,不要忘了传参lessOptions
    {
      loader: require.resolve('less-loader'),
      options: lessOptions,
    },
    
    // 3. 
    {
      test: lessRegex, 
        exclude: lessModuleRegex, 
          use: getStyleLoaders( 
            {
              importLoaders: 1, 
              sourceMap: isEnvProduction && shouldUseSourceMap, 
            }, 
            'less-loader' 
          ), 
       sideEffects: true, 
    }, 
    {
      test: lessModuleRegex, 
        use: getStyleLoaders(
          {
            importLoaders: 1, 
            sourceMap: isEnvProduction && shouldUseSourceMap,
            module: true,
            getLocalIdent: getCSSModuleLocalIdent
          },
          'less-loader'
        ),
    },
    
    
  2. npm i less less-loader --save

  3. 如果还是报错,请将less-loader===>5.0.0

路径别名
// webpack.config.js
// 1 .
const pathResolve = (url) => {
  return path.join(__dirname, url);
};

// 2. 例:
'@': pathResolve('../src')
解决兼容性
// 兼容IE浏览器
// npm i react-app-polyfill --save
// 入口文件中顶部
import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';

React 17

React和Vue的区别

相同点
  • 虚拟DOM,数据驱动,组件化
不同点:
  • react使用fiber算法,vue采用diff算法
  • react jsx语法,vue 推荐html模板
  • react 是单向数据流,vue双向数据绑定
  • react MVC,vue MVVM
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值