React API学习第一天

238 阅读5分钟

React.Component

1-如果将组件定义为ES6的class类,就必须继承这个React.Component。

2-React.Componet这个基础类中必须要有render(){}这个函数。

3-注意这句话:我们强烈建议你不要创建自己的组件基类。 在 React 组件中,代码重用的主要方式是组合而不是继承

4-对于第三点,我们可以具体看

组合 vs 继承

  1. 包含关系:{props.children}本质就是对象,将他们当作props一样传递,回一下Vue中的slot概念,但在 React 中没有“槽”这一概念的限制,你可以将任何东西作为 props进行传递。
  2. vue slot
  3. 特殊关系:{props.title}、{props.head}等组合起来
  4. 组合:props和组合为我们提供了清晰并且安全的制定复用组件的灵活方式,组件可以接受任意props,包括基本数据类型(String,Null等)、React元素(Object对象)、函数等
  5. 继承:如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript 模块,如函数、对象或者类。组件可以直接引入(import)而无需通过(extend) 继承它们,比如我们经常使用的tool.js、util.js等文件中的公用方法

5-React.Component会注入React的

生命周期函数

  1. 挂载时:construction和componentDidMount只有在挂载的时候触发一次,那么两者在父子组件中的渲染情况又是怎样的呢?下图显示可知construction和componentDidMount渲染情况是不一样的
  2. 更新时:又可以分为多种情况(父组件只更新state数据,父组件更新子组件的props数据,子组件更新state,父组件强制使用forceUpdate方法 - 隐含shouldComponentUpdate生命周期方法)
  3. 卸载时:谁卸载,谁会调用componentWillUnmount,和componentDidMount不一样。
  4. 错误处理时:componentDidCatch

render

1-render返回什么内容

  1. React元素,<div>,<MyComponent>html元素和自定义元素

  2. 数组或者fragments

    <React.Fragment> 
        <!--在真正渲染的时候Fragment不会被渲染成div或者另外元素-->
        <ChildA />
        <ChildB />
        <ChildC />
    </React.Fragment>
    
  3. Portals

    Portals = ReactDOM.createPortal(child, container) // child加载到container下面 modalRoot.appendChild(container) // container挂载到modal根节点下面

    Portals在A组件中声明,实际挂载到body下面到div中,那么Portals中到click事件冒泡会在A中出现还是body中出现?

    A组件中会出现冒泡事件

  4. 字符串或数值类型

  5. 布尔类型或 null

2-render中保持纯函数,而不要有与浏览器的交互,这些交互可以放在componentDidMount中


constructor(props)

1-是否要写构造函数,如果不需要设定state和绑定函数,那么不需要主动声明构造方法

2-在构造函数中只做两件事,设定初始state和绑定函数,对于有副作用和订阅关系的时候,放在componentDidMount中

3-千万不要将props直接赋值给state,因为你直接可以用this.props获取,这里带来的问题是,如果你更改了this.props中值,react并不会动态修改state的值,导致state的值和props的值不一致

4-一定要使用this.state.email = this.props.defaultEmail,那么父组件在子组件上绑定唯一的key,促使父组件修改props中email时,绑定在子组件上的key也修改了,迫使子组件render,从而重新获取this.props.defaultEmain的值


componentDidMount

1-请求网络数据的好地方

2-在这个地方设置了订阅,那么在componentWillUnmount一定要取消订阅

3-如果在componentDidMount中setState,重新更新state的值的时候,它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 render() 两次调用的情况下,用户也不会看到中间状态。(但是有性能问题)(这样也为什么说是请求网络数据的好地方了


componentDidUpdate(prevProps, prevState, snapshot)

1-在这里面如果setState,一定要有一个if语句,进行条件限制,否则一但更新就会render,产生一些性能问题

2-snapShot参数是,getSnapshotBeforeUpdate生命周期函数的返回值,否则为undefined

3-首次渲染不会执行此方法,更新的时候执行这个方法


componentWillUnmount()

1-取消订阅,取消timer,取消请求等等,一系列清除工作


不常用的生命周期函数

shouldComponentUpdate

1-返回Boolean,true则render或者componentDidUpdate,反之false就不渲染

2-首次渲染或者forceUpdate的时候,组件本身的shouldComponentUpdate不执行

static getDerivedStateFromProps(props, state)

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

getSnapshotBeforeUpdate

作用:snapshot 翻译就是快照,就是在更新前获取DOM元素的信息的,比如滚动条位置,比如DOM的位置,以便与componentDidUpdate,具体更新挂载DOM元素的时候,能够获取到这部分的参数


Error boundaries(错误界限)

1-static getDerivedStateFromError() 或 componentDidCatch()

2-用来展示降级UI,而不是页面崩溃

3-不要用来控制流程


setState((state, props) => stateChange, [callback])

1-setState() 将对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件。

2-将 setState() 视为请求而不是立即更新组件的命令

3-后调用的 setState() 将覆盖同一周期内先调用 setState 的值,因此商品数仅增加一次。如果后续状态取决于当前状态,我们建议使用 updater 函数的形式代替:

先:this.setState({quantity: quantity + 1})
后:this.setState({quantity: quantity + 1})

变成

Object.assign(
  previousState,
  {quantity: state.quantity + 1},
  {quantity: state.quantity + 1},
  ...
)

省略了过时生命周期函数