React 高级技巧用法笔记

React高级技巧

学一门框架,首先要熟悉官方文档,不然框架总会学得有所欠缺。尤其当使用过React一段时候后,对此深有体会。于是便依据官方文档做了以下的学习笔记。建议大家也去官方文档学习,毕竟每个人对文档的理解都有所不同。

Context上下文

作用:提供了一个无需为每层组件手动添加props,就能在组件树中进行 自上而下 数据传递的方法。 API:React.createContext() 1、使用React.createContext()创建“上下文组件” 2、在组件树的任何节点上包裹一个 注意:Provider 接受的value会传递给消费者组件,多个Provider 可以嵌套使用,里层的会覆盖外层的value数据。当Provider的value值发生改变时,其内部的所有消费者组件都会被重新渲染,Provider及其内部的消费者组件(consumer)都不会被shouldComponentUpdate 函数控制。 3、在后代组件节点上,使用 contextType属性 或者 使用Consumer使用上下文数据。 注意事项:当 provider 的父组件进行重渲染时,可能会在 consumers 组件中触发意外的渲染。为了防止这种情况,将 value 状态提升到父节点的 state 里,即(状态提升)。

JSX进行refs转发操作

在vue中当我们需要对页面DOM进行操作时,我们会用到ref。作为vue的前辈,React也会ref操作DOM的API。React.createRef()这个API可以在React中创建一个DOM元素的ref。 当然React不建议我们使用ref获取DOM元素 例如:以class组件为例

class CustomRef extends React.Component {
  constructor(props) {
    super(props);
    // 创造 DOM 元素的 ref
    this.Refs = React.createRef();
  }
  render() {
  // 使用 `ref` 回调函数以在实例的一个变量中存储文本输入 DOM 元素
  //(比如,this.Refs)。
    return (
      {console.log( this.Refs.current)} }
      />
    );
  }
}

refs不会被透传下去,因为ref不是props属性,与key一样会被React进行特殊处理

高阶组件

React 中用于复用组件逻辑的一种高级技巧。高阶组件是参数为组件,返回值为新组件的函数。由于React16.8以后有了Hook ,所以一般直接使用函数组件即可。

    //写一个装饰HOC函数 hoc/test.jsx
    import React from "react";
    export default C => () => {
    return (
        <>
            
这是装饰的头部


这是装饰的尾部
) //再写一个需要装饰的函数组件 view/T.jsx import React from "react"; import test from "../hoc/test"; export default test(()=>{ return
这是要被修饰的组件
}) // 再到入口文件中进行展示 import React from 'react'; import ReactDOM from 'react-dom'; import T from './views/T'; ReactDOM.render( , document.getElementById('root') );

React 高级技巧用法笔记_第1张图片

 除了上面的一种写法

ES7的装饰器也可以用来进行处理

例如之前的 T.jsx文件还可以这么写

import React from "react";
import test from "../hoc/test";


// export default test(()=>{
//     return 
这是要被修饰的组件
// }) @test class T extends React.PureComponent{ render(){ return(
这是要被修饰的组件
) } } export default T

因为装饰器是一个实验性的 JavaScript 提案。所以我需要安装对应的babel进行处理。

注意:

1.不要再render方法中使用HOC,因为每次调用render时,都会导致子组件被重新渲染,这不仅仅消耗性能,而且重现挂载组件还会导致该组件及其所有子组件状态的丢失。

2.静态方法需要复制,React文档中有提到,当使用HOC应用于组件时,原始的组件将会被使用容器进行包装。这会导致新组建中没有原始组件的任何静态方法。所以我们需要在其放回之前将这些方法拷贝到容器组件上。React官方推荐我们使用 hoist-non-react-statics 自动拷贝所有非 React 静态方法: 

import hoistNonReactStatic from 'hoist-non-react-statics';
function enhance(WrappedComponent) {
  class Enhance extends React.Component {/*...*/}
  hoistNonReactStatic(Enhance, WrappedComponent);
  return Enhance;
}

3.Refs不会被传递, 原因很简单,ref与key一样会被React在编译过程中被处理。官方也给出了解决方案使用 React.forwardRef 这个API。

4.props属性需要继承,在封装高阶组件时以防属性的丢失,我们一定要添加属性的继承。

Hook

什么是Hook

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。

Hook API的操作直达React底层,所以性能更好、效率更高、代码也更加简洁。

为什么建议使用Hook

使用class组件会带来一些问题,例如:class不能很好的被压缩,并且热重载时不太稳定。基于这些问题,React建议我们使用Hook,因为Hook能是代码更易于优化。

我们使用Hook API可以模拟出class组件大多数的特性,比如 state、生命周期、上下文、ref等。

Hook常用的几个API有useState, useEffect, useMemo, useContext, useCallback

Hook的使用之State Hook

这是一种在函数调用时保存变量的方式 —— useState 是一种新方法,它与 class 里面的 this.state 提供的功能完全相同。一般来说,在函数退出后变量就会”消失”,而 state 中的变量会被 React 保留。

useState() 唯一的参数就是存放初始的state值。其state值的类型 可以是数字、字符串或者对象等。

setState React 会在重复渲染时记住它当前的值,并且提供最新的值给我们的函数。我们可以通过调用 setState 来更新当前的 state

import React, { useState } from 'react';
export default () => {
  //useState用来声明一个变量  这个初始出来的state参数只在第一次渲染时会被被创建
  //其中 num为被声明的变量名,我们可以通过调用setNum来修改这个变量
    const [num, setNum] = useState(123);
    return (
      // 这个为React的随便化语法
        
          
{num}
setNum(num+1)}>自增
) }

 建议:将 state 变量声明为一对 [something, setSomething]方便在开发中查找使用。

为什么使用“数组解构”?因为这样能利用数组位置进行赋值操作。

Hook的使用之 Effect Hook

当需要进行一些有阻碍js的操作或性能消耗的操作时,我们可以使用useEffect来对这些“副作用”进行处理。

我们可以把 useEffect Hook 看做  componentDidMountcomponentDidUpdate 和 componentWillUnmount 这三个函数的组合。

为什么在组件内部调用 useEffect

        将 useEffect 放在组件内部让我们可以在 effect 中直接访问  state 变量(或其他 props)

useEffect 会在每次渲染后都执行吗? 

        是的,默认情况下,它在第一次渲染之后每次更新之后都会执行。React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。

注意:使用 useEffect 调度的 effect 不会阻塞浏览器更新屏幕。(异步操作)

代码示例:

useEffect(()=>{
    // 这里相当于componentDidMount()
    let time = setInterval(()=>{
        console.log(Date.now())
    },1000)

    return ()=>{
        //这里相当于componentWillUnmount()
        // 清除函数,用来操作一些需要清除的数据,例如:组件销毁后清除定时器
        clearInterval(time);
        time = null;
        console.log("组件要卸载了");
    }
},[])

useEffect的用法:两个参数:第一个参数是需要进行的操作和一个return ,在return中存放清除这个操作的影响,例如使用了定时器,当我们销毁这个组件时,我们就需要清除定时器对全局的影响,第二个参数:  触发条件,当第二个参数为空时,每当页面需要重新渲染时,useEffect都会被调用执行当第二个参数为空数组时,useEffect只会在组件创建时执行一次,会通知 React 跳过对 effect 的调用;当第二个参数为数组(可以有多个元素)时,会监听其中的参数是否发生改变,当参数发生改变就会通知 React对 effect 的调用。

Hook的使用之Context Hook

const value = useContext(MyContext);

接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定。

当组件上层最近的  更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value 值。即使祖先使用React.memo 或shouldComponentUpdate ​​​,也会在组件本身使用 useContext 时重新渲染。

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

const ThemeContext = React.createContext(themes.light);

function App() {
  return (
    
      
    
  );
}

function Toolbar(props) {
  return (
    
); } function ThemedButton() { const theme = useContext(ThemeContext); return ( ); }

Hook规则

只在最顶层使用 Hook,不要在循环,条件或嵌套函数中调用 Hook。确保Hook总会在函数最顶层被调用,以确保Hook在每一次渲染时都被会被按照同样的顺序被调用。

ESLint插件 :eslint-plugin-react-hooks 

npm install eslint-plugin-react-hooks --save-dev
        
// 你的 ESLint 配置
{
  "plugins": [
    // ...
    "react-hooks"
  ],
  "rules": {
    // ...
    "react-hooks/rules-of-hooks": "error", // 检查 Hook 的规则
    "react-hooks/exhaustive-deps": "warn" // 检查 effect 的依赖
  }
}

自定义Hook 

自定义Hook一般是“use**”的格式命名,我们可以通过封装一个符合自定义规则命名的Hook调用其他的Hook,Hook函数内部可以调用其他的 Hook。

当然,如果不想造轮子的话,我们可以使用 react-use 库,该库封装了需要我们常用到的一些方法。

自定义 Hook 必须以 “use” 开头,不遵循的话,由于无法判断某个函数是否包含对其内部 Hook 的调用,React 将无法自动检查你的 Hook 是否违反了Hook规则。

在两个组件中使用相同的 Hook 不会共享 state,Hook是一种重用状态逻辑的机制,所以在不同组件的 Hook中的所有state和副作用都是完全隔离的。

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