React 知识总结

1. context

  1. 创建一个Context对象

const MyContext = React.createContext(defaultValue);

注意 : 将 undefined 传递给 Provider 时,消费组件的 defaultValue 不会生效。

  1. context.Provider

<MyContext.Provider value={ /* 某个值 */ }>

  • 当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染。Provider 及其内部 consumer 组件都不受制于 shouldComponentUpdate 函数,因此当 consumer 组件在其祖先组件退出更新的情况下也能更新。

3.contextType


class MyClass extends React.Component {

  static contextType = MyContext;

  render() {

    let value = this.context;

    /* 基于这个值进行渲染工作 */

  }}

  //也可以在类的外部写成如下: Mycontext是在2中定义的

  My.contextType = Mycontext

  1. Context.Consumer

<MyContext.Consumer>

  { value => /* 基于 context 值进行渲染*/ }</MyContext.Consumer>

  • 这里,React 组件也可以订阅到 context 变更。这能让你在函数式组件中完成订阅 context。

  • 这需要函数作为子元素(function as a child)这种做法。这个函数接收当前的 context 值,返回一个 React 节点。传递给函数的 value 值等同于往上组件树离这个 context 最近的 Provider 提供的 value 值。如果没有对应的 Provider,value 参数等同于传递给 createContext() 的 defaultValue。

  1. 动态Context

import React from 'react';

const themes = {

    light: {

        color: 'blue',

        background: 'red',

    },

    dark: {

        color: '#ffffff',

        background: '#000000',

    },

};

const ThemeContext = React.createContext(

    themes.dark // 默认值

);

class ThemedButton extends React.Component {

    static contextType = ThemeContext;

    render() {

        let props = this.props;

        let theme = this.context;

        console.log(props,theme)

        return (

            <button

            {...props}

            style={{backgroundColor: theme.background ,color:theme.color, width:"200px" , height:"100px"}}

            />

        );

    }

}

function Toolbar(props) {

    return (

        <ThemedButton onClick={props.changeTheme}>

            {props.changeTheme?'我是用的上级传下来的属性':'我是默认值'}

        </ThemedButton>

    );

}

class App extends React.Component {

    constructor(props) {

    super(props);

    this.state = {

        theme: themes.light,

    };

    this.toggleTheme = () => {

        this.setState(state => ({

                theme:

                state.theme === themes.dark ? themes.light : themes.dark,

            }));

        };

    }

    render() {

    // 在 ThemeProvider 内部的 ThemedButton 按钮组件使用 state 中的 theme 值,

    // 而外部的组件使用默认的 theme 值

        return (

            <>

                <ThemeContext.Provider value={this.state.theme}>

                    <Toolbar changeTheme={this.toggleTheme} />

                </ThemeContext.Provider>

                <Toolbar />

            </>

        );

    }

}

export default App;

2.错误边界

1.注意错误边界无法捕获以下场景中产生的错误:

  • 事件处理(了解更多)

  • 异步代码(例如 setTimeout 或 requestAnimationFrame 回调函数)

  • 服务端渲染

  • 它自身抛出来的错误(并非它的子组件)


  1. 如果一个 class 组件中定义了 static getDerivedStateFromError() 或 componentDidCatch() 这两个生命周期方法中的任意一个(或两个)时,那么它就变成一个错误边界。当抛出错误后,请使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息。

class ErrorBoundary extends React.Component {

  constructor(props) {

    super(props);

    this.state = { hasError: false };

  }

  static getDerivedStateFromError(error) { 

      // 更新 state 使下一次渲染能够显示降级后的 UI 

      return { hasError: true };

  } 

  componentDidCatch(error, info) { 

      // 你同样可以将错误日志上报给服务器   

      logErrorToMyService(error, info); 

  }

  render() { 

  if (this.state.hasError) {     

      // 你可以自定义降级后的 UI 并渲染     

      return <h1>Something went wrong.</h1>; 

  }

    return this.props.children;

  }}

Refs转发

定义 :Ref 转发是一项将 ref 自动地通过组件传递到其一子组件的技巧。对于大多数应用中的组件来说,这通常不是必需的。但其对某些组件,尤其是可重用的组件库是很有用的。最常见的案例如下所述。


  1. 何时使用Refs
  • 管理焦点,文本选择或媒体播放。

  • 触发强制动画。

  • 集成第三方 DOM 库


  1. 创建Refs:Refs 是使用 React.createRef() 创建的,并通过 ref 属性附加到 React 元素。在构造组件时,通常将 Refs 分配给实例属性,以便可以在整个组件中引用它们。

class MyComponent extends React.Component {

  constructor(props) {

        super(props);   

        this.myRef = React.createRef();

    }

  render() { 

  return <div ref={this.myRef} />;

  }

}


  1. 访问Refs:当 ref 被传递给 render 中的元素时,对该节点的引用可以在 ref 的 current 属性中被访问。

const node = this.myRef.current;


  1. ref 的值根据节点的类型而有所不同:
  • 当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性。

  • 当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性。

  • 你不能在函数组件上使用 ref 属性,因为他们没有实例。

Fragments

  1. 定义:Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点。

< Fragments > < /Fragments > 或者<></>

高阶组件

  1. 定义:高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。

  1. 高阶组件是参数为组件,返回值为新组件函数

  1. 注意:HOC 不会修改传入的组件,也不会使用继承来复制其行为。相反,HOC 通过将组件包装在容器组件中来组成新组件。HOC 是纯函数,没有副作用。

  1. 虽然高阶组件的约定是将所有 props 传递给被包装组件,但这对于 refs 并不适用。那是因为 ref 实际上并不是一个 prop - 就像 key 一样,它是由 React 专门处理的。如果将 ref 添加到 HOC 的返回组件中,则 ref 引用指向容器组件,而不是被包装组件。

深入JSX

  1. 实际上,JSX 是 React.createElement(component, props, ...children) 函数的语法糖。

  1. 大写字母开头的 JSX 标签意味着它们是 React 组件。这些标签会被编译为对命名变量的直接引用,所以,当你使用 JSX <Foo /> 表达式时,Foo 必须包含在作用域内。

  1. 如果你没给 prop 赋值,它的默认值是 true

<MyTextBox autocomplete />

//这俩表达式完全等价

<MyTextBox autocomplete={true} />


  1. 如果你已经有了一个 props 对象,你可以使用展开运算符... 来在 JSX 中传递整个 props 对象

function App1() {

  return <Greeting firstName="Ben" lastName="Hector" />;}

function App2() {

  const props = {firstName: 'Ben', lastName: 'Hector'};

  return <Greeting {...props} />;

  }


  1. false, null, undefined, and true 是合法的子元素。但它们并不会被渲染。以下的 JSX 表达式渲染结果相同;

  1. 值得注意的是有一些 “falsy” 值,如数字 0,仍然会被 React 渲染。例如,以下代码并不会像你预期那样工作,因为当 props.messages 是空数组时,0 仍然会被渲染:

<div>

    {props.messages.length && <MessageList messages={props.messages} />

    }

</div>

要解决这个问题,确保 && 之前的表达式总是布尔值:


<div>

    {props.messages.length > 0 &&    <MessageList messages={props.messages} />

    }

</div>

反之,如果你想渲染 false、true、null、undefined 等值,你需要先将它们转换为字符串:


<div>

My JavaScript variable is {String(myVariable)}

.</div>

性能优化

  1. 确保你正在使用压缩后的生产版本

  2. Immutable.js

  3. 更多请自行百度

Portals

定义:Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。


  1. 第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment。第二个参数(container)是一个 DOM 元素。

ReactDOM.createPortal(child, container)

  1. 通常来讲,当你从组件的 render 方法返回一个元素时,该元素将被挂载到 DOM 节点中离其最近的父节点:

render() {

  // React 挂载了一个新的 div,并且把子元素渲染其中

      return ( 

      <div>{this.props.children}</div>

      );

  }

然而,有时候将子元素插入到 DOM 节点中的不同位置也是有好处的:

render() {

  // React 并*没有*创建一个新的 div。它只是把子元素渲染到 `domNode` 中。

  // `domNode` 是一个可以在任何位置的有效 DOM 节点。

  return ReactDOM.createPortal(

    this.props.children,    domNode

  );

}

一个 portal 的典型用例是当父组件有 overflow: hidden 或 z-index 样式时,但你需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框:

使用 PropTypes 进行类型检查

  1. 注意 : 自 React v15.5 起,React.PropTypes 已移入另一个包中。请使用 prop-types 库 代替。

  2. 使用方法


import PropTypes from 'prop-types';

class Greeting extends React.Component {

  render() {

    return (

      <h1>Hello, {this.props.name}</h1>

    );

  }

}

Greeting.propTypes = {

  name: PropTypes.string

};


import PropTypes from 'prop-types';

MyComponent.propTypes = {

  // 你可以将属性声明为 JS 原生类型,默认情况下

  // 这些属性都是可选的。

  optionalArray : PropTypes.array,

  optionalBool : PropTypes.bool,

  optionalFunc : PropTypes.func,

  optionalNumber : PropTypes.number,

  optionalObject : PropTypes.object,

  optionalString : PropTypes.string,

  optionalSymbol : PropTypes.symbol,

  // 任何可被渲染的元素(包括数字、字符串、元素或数组)

  // (或 Fragment) 也包含这些类型。

  optionalNode : PropTypes.node,

  // 一个 React 元素。

  optionalElement : PropTypes.element,

  // 一个 React 元素类型(即,MyComponent)。

  optionalElementType : PropTypes.elementType,

  // 你也可以声明 prop 为类的实例,这里使用

  // JS 的 instanceof 操作符。

  optionalMessage : PropTypes.instanceOf(Message),

  // 你可以让你的 prop 只能是特定的值,指定它为

  // 枚举类型。

  optionalEnum : PropTypes.oneOf(['News', 'Photos']),

  // 一个对象可以是几种类型中的任意一个类型

  optionalUnion : PropTypes.oneOfType([

    PropTypes.string,

    PropTypes.number,

    PropTypes.instanceOf(Message)

  ]),

  // 可以指定一个数组由某一类型的元素组成

  optionalArrayOf: PropTypes.arrayOf(PropTypes.number),

  // 可以指定一个对象由某一类型的值组成

  optionalObjectOf: PropTypes.objectOf(PropTypes.number),

  // 可以指定一个对象由特定的类型值组成

  optionalObjectWithShape: PropTypes.shape({

    color: PropTypes.string,

    fontSize: PropTypes.number

  }),



  // An object with warnings on extra properties

  optionalObjectWithStrictShape: PropTypes.exact({

    name: PropTypes.string,

    quantity: PropTypes.number

  }), 

  // 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保

  // 这个 prop 没有被提供时,会打印警告信息。

  requiredFunc: PropTypes.func.isRequired,

  // 任意类型的数据

  requiredAny: PropTypes.any.isRequired,

  // 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。

  // 请不要使用 `console.warn` 或抛出异常,因为这在 `onOfType` 中不会起作用。

  customProp: function(props, propName, componentName) {

    if (!/matchme/.test(props[propName])) {

      return new Error(

        'Invalid prop `' + propName + '` supplied to' +

        ' `' + componentName + '`. Validation failed.'

      );

    }

  },

  // 你也可以提供一个自定义的 `arrayOf` 或 `objectOf` 验证器。

  // 它应该在验证失败时返回一个 Error 对象。

  // 验证器将验证数组或对象中的每个值。验证器的前两个参数

  // 第一个是数组或对象本身

  // 第二个是他们当前的键。

  customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {

    if (!/matchme/.test(propValue[key])) {

      return new Error(

        'Invalid prop `' + propFullName + '` supplied to' +

        ' `' + componentName + '`. Validation failed.'

      );

    }

  })};

React.Component

  1. render() 方法是 class 组件中唯一必须实现的方法。

  2. constructor()

如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。

  1. 通常,在 React 中,构造函数仅用于以下两种情况:
  • 通过给 this.state 赋值对象来初始化内部 state。

  • 为事件处理函数绑定实例


  1. 在 constructor() 函数中不要调用 setState() 方法。如果你的组件需要使用内部 state,请直接在构造函数中为 this.state 赋值初始 state

constructor(props) {

  super(props);

  // 不要在这里调用 this.setState()

  this.state = { counter: 0 };

  this.handleClick = this.handleClick.bind(this);

}


  1. 避免将 props 的值复制给 state!这是一个常见的错误:

componentDidMount()钩子

  1. 调用时机以及主要作用
  • componentDidMount() 会在组件挂载后(插入 DOM 树中)立即调用。

  • 依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。

componentDidUpdate(prevProps, prevState, snapshot)

  1. componentDidUpdate() 会在更新后会被立即调用。首次渲染不会执行此方法。

  2. 你也可以在 componentDidUpdate() 中直接调用 setState(),但请注意它必须被包裹在一个条件语件里,否则会导致死循环。

  3. 注意 : 如果 shouldComponentUpdate() 返回值为 false,则不会调用 componentDidUpdate()。

componentWillUnmount()

  • componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。

  • componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。

shouldComponentUpdate(nextProps, nextState) 不常用

  1. 此方法仅作为性能优化的方式而存在。不要企图依靠此方法来“阻止”渲染,因为这可能会产生 bug。你应该考虑使用内置的 PureComponent 组件,而不是手动编写

  2. 首次渲染或使用 forceUpdate() 时不会调用该方法。

  3. 返回值默认为true , 若为false则不渲染该组件,但子组件的state变化依旧会进行渲染子组件

static getDerivedStateFromProps(props, state)

调用时机 : 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state(相当于merge),如果返回 null则不更新任何内容。

getSnapshotBeforeUpdate(prevProps, prevState)

  1. 调用时机 : getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。

static getDerivedStateFromError(error)

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


class ErrorBoundary extends React.Component {

  constructor(props) {

    super(props);

    this.state = { hasError: false };

  }

  static getDerivedStateFromError(error) { 

      // 更新 state 使下一次渲染可以显降级 UI 

      return { hasError: true };

  }

  render() { 

  if (this.state.hasError) {   

      // 你可以渲染任何自定义的降级  UI   

      return <h1>Something went wrong.</h1>; 

  }

    return this.props.children;

  }}

componentDidCatch(error, info)

此生命周期在后代组件抛出错误后被调用。 它接收两个参数:

  • error —— 抛出的错误

  • info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息。

setState()

  1. 这个是异步的 , 如果想再一次回调中执行多次setState(),请使用回调函数的方式或者componentDidUpdate

  2. 除非 shouldComponentUpdate() 返回 false,否则 setState() 将始终执行重新渲染操作。

  3. 函数式setState


this.setState((state, props) => {

    return { counter: state.counter + props.step };

  }

);

  1. 直接赋值式

this.setState({quantity: 2})

forceUpdate(callback)

  • 默认情况下,当组件的 state 或 props 发生变化时,组件将重新渲染。如果 render() 方法依赖于其他数据,则可以调用 forceUpdate() 强制让组件重新渲染。

  • 调用 forceUpdate() 将致使组件调用 render() 方法,此操作会跳过该组件的 shouldComponentUpdate()。但其子组件会触发正常的生命周期方法,包括 shouldComponentUpdate() 方法。如果标记发生变化,React 仍将只更新 DOM。

defaultProps

defaultProps 可以为 Class 组件添加默认 props。这一般用于 props 未赋值,但又不能为 null 的情况。例如:


class CustomButton extends React.Component {

  // ...

  }

CustomButton.defaultProps = {

  color: 'blue'

  };

如果未提供 props.color,则默认设置为 'blue'


  render() {

    return <CustomButton /> ;

    // props.color 将设置为 'blue'

  }

如果 props.color 被设置为 null,则它将保持为 null


  render() {

    return <CustomButton color={null} /> ;

    // props.color 将保持是 null

  }

ReactDOM

如果你使用一个 <script> 标签引入 React,所有的顶层 API 都能在全局 ReactDOM 上调用。如果你使用 npm 和 ES6,你可以用 import ReactDOM from 'react-dom'。


import ReactDOM from 'react-dom'

ReactDOM.render(element, container[, callback])

什么是单页面应用

单页面应用(single-page application),是一个应用程序,它可以加载单个 HTML 页面,以及运行应用程序所需的所有必要资源(例如 JavaScript 和 CSS)。与页面或后续页面的任何交互,都不再需要往返 server 加载资源,即页面不会重新加载。

记住,props 是只读的。不应以任何方式修改它们

props.children

每个组件都可以获取到 props.children。它包含组件的开始标签和结束标签之间的内容。例如:


<Welcome>Hello world!</Welcome>

在 Welcome 组件中获取 props.children,就可以得到字符串 Hello world!:

受控组件VS非受控组件

  • 如果一个 input 表单元素的值是由 React 控制,就其称为受控组件。当用户将数据输入到受控组件时,会触发修改状态的事件处理器,这时由你的代码来决定此输入是否有效(如果有效就使用更新后的值重新渲染)。如果不重新渲染,则表单元素将保持不变。

  • 一个非受控组件,就像是运行在 React 体系之外的表单元素。当用户将数据输入到表单字段(例如 input,dropdown 等)时,React 不需要做任何事情就可以映射更新后的信息。然而,这也意味着,你无法强制给这个表单字段设置一个特定值。

  • 在大多数情况下,你应该使用受控组件。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容

  • 作为一个合格的开发者,不要只满足于编写了可以运行的代码。而要了解代码背后的工作原理;不要只满足于自己的程序...
    六个周阅读 8,441评论 1 33
  • 40、React 什么是React?React 是一个用于构建用户界面的框架(采用的是MVC模式):集中处理VIE...
    萌妹撒阅读 1,014评论 0 1
  • 3. JSX JSX是对JavaScript语言的一个扩展语法, 用于生产React“元素”,建议在描述UI的时候...
    pixels阅读 2,823评论 0 24
  • 深入JSX date:20170412笔记原文其实JSX是React.createElement(componen...
    gaoer1938阅读 8,061评论 2 35
  • 1、什么是react React.js 是一个帮助你构建页面 UI 的库。React.js 将帮助我们将界面分成了...
    谷子多阅读 2,557评论 1 13