react入门三

ReactDOM.render(<MyComponent/>, document.getElementById("root"))发生了什么

react解析MyComponent标签找到了MyComponent组件,发现组件是类定义的,随后new出该类的实例,并通过该实例调用到原型上的render方法
将render方法返回的虚拟dom转为真实dom,随后呈现在页面中,呈现后还会调用一个componentDidMount

ref

  • 字符串的形式(不推荐使用,存在性能问题)

  • 回调的方式
    <input ref={(currentNode) => {this.input = currentNode}}/>, 该回调一上来就会调用一次
    PS: 向上面这种回调的方式(内联的方式)在更新的时候会调用两次,注意是更新的时候,第一次currentNode为null(因为每次render都会创建一个新的内联函数,当更新的时候第一次调用是为了清空就得函数,所以返回一个null),第二次才会把节点传入. 如果非得解决这个问题,react也提供了方案,通过类绑定的方式:

    <input ref={this.saveInput}/>,

    在class里面定义saveInput

    saveInput = (c) => { // c就是传入的node节点
    this.input1 = c;
    }

createRef

class Demo extends React.Compoent{
    myRef = React.createRef(); // createRef返回一个容器,该容器用于存放被ref所标识的节点,该容器专人专用只能绑定一个,因此后放进去的会覆盖之前的,如果想使用多个就需要createRef多次
    render() {
        return (
            <input ref={this.myRef}/> {/*这里相当于将input存放到了myRef中了,input节点可以通过this.myRef.current访问*/}
        ) 
    }
}

react中的事件

  • 1 通过onXXX属性指定事件处理函数
    react中使用的是自定义事件(合成事件,而不是使用原生的dom事件)--- 是为了更好的兼容性

      react中的事件是通过事件委托的方式处理的(委托给组件最外层元素)--- 事件委托的原理是事件冒泡,使用事件委托高效
    
  • 2 通过event.target得到发生事件的dom元素对象

收集表单数据

  • 非受控组件

    现用现取,通过ref可以完成

  • 受控组件

    输入类的元素在随着输入将值维护到状态中

高阶函数和柯里化

高阶函数:
若函数A接受的参数是一个函数,那么A就称之为高阶函数
若函数A调用的返回值依然是一个函数,那么A就称之为高阶函数
常见的高阶函数:如Promise, setTimeout, 数组的常用方式
函数柯里化
部分求值,函数的调用仍旧返回函数,实现多次接受参数最后统一处理的函数编码

生命周期

组件从创建到死亡会经历一些特定的阶段

React组件中包含一系列钩子函数,会在特定的时刻调用

在定义组件时,会在特定的声明周期回调函数中做特定的工作

  • 旧版的生命周期钩子

组件挂载的执行顺序
constructor ---> componentWillMount ---> render ---> componentDidMount ---> componentWillUnmount

组件更新执行顺序(可以分为3条线)

父组件渲染子组件,当传入的数据更新时的执行路线

componentWillReceiveProps ---> shouldComponentUpdate ---> componenWillUpdate ---> render ---> componentDidUpdate ---> componentWillUnmount

当组件setState更新的时候

setState() ---> shouldComponentUpdate ---> componentWillUpdate ---> render ---> componentDidUpdate ---> componentWillUnmount

当强制更新组件的时候(不更改状态数据就想让组件更新就可以走这条线)

forceUpdate() ---> componentWillUpdate ---> render ---> componentDidUpdate ---> componentWillUnmount

ps: shouldComponentUpdate是一个阀门钩子,如果不写这个钩子默认返回true,接下来的流程正常执行,如果写了并且返回false则接下来的流程不会执行,只能返回true或者false,

componentWillReciveProps 这个钩子第一次不调用,只有接受的props变化了才会调用,也就是父组件重新渲染导致子组件渲染才执行该钩子,接受新的props。

总结:

初始化阶段
constructor ---> componentWillMount ---> render() ---> componentDidMount
更新阶段: 由组件内部this.setState() 或者父组件更新触发
shouldComponentUpdate ---> componentWillUpdate ---> render ---> componentDidUpdate

卸载阶段:由reactDOM.unmountComponentAtNode(node)触发
componentWillUnmount()

常用的钩子:
componentDidMount: 一般做初始化操作例如开启定时器,发送网络请求,订阅消息。。。

componentWillUnmount: 做一些收尾工作如取消定时器,取消订阅等

render: 必须用,需要掉1+n次

  • 新的声明周期 (react最新版本)

所有带will的钩子在新版版中都加了UNSAFE_前缀, 除了卸载的钩子,为什么这么做,因为react在设计异步渲染,这些组件可能会出现bug,以后可能会被废弃

新版本废弃了componentWillMount, componentWillUpdate, componentWillReciveProps,新增了getDerivedStateFromProps 和getSnapshotBeforeUpdate

需要注意的是 getDerivedStateFromProps不能在实例上调用,需要声明成静态的需要加static, 而且该方法必须要有返回值,要么你返回状态对象,要么返回null,不能返回其他的。需要注意的是只要返回一个对象,那么状态的更新就没有意义了,因为一旦返回状态,此状态就不能被改了,该方法接收一个参数props, 他会接收props属性并且会派生出一个取决于props的状态。可以接收第二个参数state,使用场景罕见,基本不用。

getSnapshotBeforeUpdate: 该钩子处于render和componentDidUpdate之间,用于在更新之前获取快照,因为更新后之前的状态就不见了,在更新之前再看一眼之前的状态。

componentDidUpdate() 该钩子会接收三个参数,第一个是更新前的props,第二个是更新前的state,第三个是一个快照值(即getSnapshotBeforeUpdate返回的值。)
挂载时:

constructor ---> getDerivedStateFromProps ---> render (react更新dom和refs) ---> componentDidMount

更新:

(new props | setState() | forceUpdate)时 ---> getDerivedStateFromProps(得到一个派生的状态) ---> shouldComponentUpdate

dom的diff算法

class Person extends React.Component{
   state = {
       persons: [
           {id: 2, name: '小张', age: 23},
           {id: 3, name: '小李', age: 19}
       ]
   }

   render() {
       return (
           <ul>
               {
                   this.state.persons.map((person,index) => {
                       return <li key={index}>{person.name}</li>
                   })
               }
           </ul>
       )
   }
}


虚拟dom中的key有什么作用?

简单说key是虚拟dom对象的标识,在更新显示是key起着极其重要的作用,,

详细说,当状态中的数据发生变化的时候,react会根据新的数据生成新的虚拟dom,随后react进行新虚拟dom和就虚拟dom的diff对比,比较规则如下:
- 就虚拟dom中找到了与新虚拟dom中相同的key:
    1) 若虚拟dom中内容没有变化,直接使用之前的真实dom
    2) 若虚拟dom中内容变了,则生成新的真实dom,随后替换页面中之前的真实dom


- 旧虚拟dom中没有找到与新虚拟dom相同的key

    根据数据创建新的真实dom,随后渲染到页面。

用index作为key可能会引发的问题:

- 若对数据进行逆序添加,逆序删除等破坏顺序操作,会产生没有必要的真实DOM更新 ==》 界面效果没问题,但是效率低

- 如果页面中还包含输入类的dom:
    会产生错误dom更新==》 界面有问题

注意,如果不存在对数据逆序添加删除等破坏顺序的操作,仅用于渲染列表,展示列表,使用index是没有问题的

<input type="checkbox"/> 这样的输入内容在react中有一个defaultChecked属性,可以代替checked属性,因为使用checked,则必须使用onchange来修改其值

react组件通讯

  • 父子组件 通过props可以通信

  • 兄弟组件 可以提取共同状态到公共父组件或者使用消息的发布订阅,或者使用redux之类的状态管理库

消息的发布订阅实现兄弟组件之间的通信常用的三方库有pubsubjs

react路由

  • 前端路由的工作原理

    依托的是浏览器历史记录,可以借助history这个库来完成操作

  • react-router-dom

    路由组件
    会自动给组件传入路由相关的props
    NavLink可以实现路由的高亮,通过activeClassName指定样式名
    标签体内容是一个特殊的标签属性
    通过this.props.children可以获取标签体内容
    路由组件一般放在pages目录
    一般组件
    一般放在components目录

    • Switch组件

      该组件会提高性能,如果不适用他,那么在匹配到目标组件后还会继续往下匹配,使用了他,当匹配到目标组件后就不会网下匹配其他组件了

    • 解决多级路径页面刷新样式丢失的问题

      • public/index.html中引入样式时不写./而是写/
      • public/index.html中引入样式时不写./ 而是%PUBLIC_URL%
      • 不要使用HistoryRouter而是使用HashRouter
    • 路由的严格模式与模糊匹配
      不是非必要情况下不要用严格模式,比如有二级路由的情况下使用了严格模式就会出问题,如/home /home/mian 当使用了严格模式, 那么/home/main永远匹配不到

    • Redirect的使用

      Redirect放在注册路由的最后,当所有路由没有匹配的时候提供一个默认的路由

    • 嵌套路由

      • 注册子路由的时候要写上父路由的path
      • 路由的匹配是按照路由的注册顺序进行的
    • 向路由组件传递params

    路由导航向路由组件传递params参数
    <Link to={`home/message/detail/${id}`}>
    // 可以传递多个参数
    <Link to={`home/message/detail/${id}/${title}`}> // 相当于传递了一个id,一个title
    注册的路由
    
    <Route path="/home/message/detail/:id" component={Detail}>
     // 可以接收多个参数
    <Route path="/home/message/detail/:id/:title" component={Detail}>
    Detail组件通过props参数就能接收到参数,在接收到的match里面就有传递的参数
    
    
- 向路由组件传递search参数

```
<Link to={`home/message/detail/?id=${id}&title=${title}`}> // 相当于传递了一个id,一个title

接受的方式(无需声明正常注册路由即可)
<Route path="/home/message/detail" component={Detail}>

Detail组件通过this.props.location.search获取,获取到的是一个字符串,我们需要的是对象的格式,因此需要特殊处理,安装脚手架的时候其实下载了一个叫做querystring的库,通过这个库可以帮我们完成
import qs from 'querystring';

// 通过qs.stringify(obj) 可以将一个对象转为key=value&key=value的格式
// 通过qs.parse(str) 可以将一个key-value格式的字符串变成对象

```
  • 向路由组件传递state参数 (这里的state不是路由状态的state)

    无论是params参数还是search参数都在地址栏上,还可以通过对象的方式去传递,此时的to属性只能是一个对象,不再是字符串了,
    需要注意的是这种方式传递参数虽然地址栏上没有参数,但是刷新的时候同样不会丢失参数,因为他是存在history中的,如果是HashRouter刷新会丢失

```
<Link to={{pathname:`/home/message/detail`, state: {id: id, title: title}}}>

// 接受state
通过this.props.location.state可以获取

```

- push 与 replace

历史记录是一个压栈模式,默认是push,如果要开启replace需要这么写, replace是替换模式
<Link replace to={{pathname:`/home/message/detail`, state: {id: id, title: title}}}>

- 编程时路由导航

通过脚本的方式进行跳转。路由组件通过this.props.history可以拿到history对象,里面包含操作历史的方法,需要注意的是编程时路由跳转时注册路由需要对应,也就是说通过search跳转的不能以params的方式注册路由,其他同理,params和query的参数在地址栏好理解,state的不再地址栏,但是同理对应的方式也有第二个参数可以接收state, 如this.props.history.push(path, state)

编程时路由导航的几个api:
* this.props.history.push
* this.props.history.replace
* this.props.history.goBack
* this.props.history.goForward
* this.props.history.goBack
* this.props.history.go

- withRouter

路由组件里面可以获取到操作历史的方法,但是再非路由组件里面是没有这些的。可以借助withRouter使一般组件也能获取到history
import {withRouter} from 'react-router-dom'

比如
export default withRouter(Header) ; 通过withRouter将一般组件Header加工后暴露,此时使用header组件就会有history相关的内容


- BrowserRouter与HashRouter的区别

 * 底层原理不一样,BrowserRouter使用的是H5的history API,不兼容Ie9及以下版本HashRouter使用的是url的hash值
 * url表现形式不一样,HashRouter带#
 * 刷新后对路由state的影响
    BrowserRouter没有影响,因为state保存在history对象中
    HashRouter会丢失state参数

* HashRouter可以用于解决一些路径错误相关的问题

redux

  • redux是什么

    • 1.1 redux是专门做状态管理的库不是react插件
    • 1.2 可以用在react,vue,angular中,但基本与react搭配使用
    • 1.3 专门做集中式状态管理,管理应用中多个组件共享的状态
  • 什么情况下用redux

    • 1.1 某个组件的状态需要让其他组件随时拿到(共享)
    • 1.2 一个组件需要改变另一个组件的状态(通信)
  • redux的工作流程

    有一个核心store,里面的值只能通过reducer更改,当用户在组件中派发一个action的时候。action不是特殊的东西,他是一个带有type和数据的对象比如{type: "INCREAMENT", data: {count: 1}}就是一个action,
    通过dispatch可以将action交给store,store不干活,他会让reducer去更改状态。reduer将状态加工完毕会返回一个新的状态给store。reducer能加工状态,那个状态哪里来?其实reducer干了两件事,一是初始化状态,二是加工状态。action creator是一个返回action对象的东西。

  • redux的三个核心概念

    • 1 action 是一个动作对象包含两个属性

      • type 标识属性,值为字符串,唯一,必要属性
      • data 数据属性,值类型任意,可选属性

      action分同步action(一般对象) 和异步action(是一个函数),一个异步的action一定对应一个同步的action,使用异步action需要一个中间件,因为action需要的是一个对象,而不是一个函数,因此需要安装redux-thunk,引入后 需要在创建store的时候作为第二个参数传递,异步的action是通过store帮助调用的

      import {createStore, applyMiddleware} from 'redux'
      import thunk from 'redux-thunk'
      
      createStroe(reducers, applyMiddleware(thunk)) 这里的reducers是个多个reducer,以对象的方式去组织,因为对象的key-value存值和取值更方便。因此reducers的结构应该是这样,是多个reducer合并的结果
      
      首先引入一个函数将所有的reducer合并为一个总的reducer
      import {combineReducers} from 'redux'
      const allReducers = combineReducers({
          countRecuder,
          otherReducer,
          ...
      });
      
    • 2 reducer 用于初始化状态,加工状态,加工时根据旧的state和action,产生新的state的纯函数

        该函数接受两个参数,第一个是之前的状态,第二个是action对象,初始化的时候第一个参数是undefined,在创建store的时候会传递reducer进去,内部会调用reducer进行状态初始化
      
        reducer必须是纯函数,纯函数,一个函数只要接受同样的实参,那么一定得到同样的结果,不能改写参数的数据
      
        ```
        比如:
        let arr = [1,2,3];
        arr.push(4); 虽然arr的内容变了,但是arr的地址引用没有变,这样的变化redux是不认的。这样写才可以
      
        [4, ...arr];这样得到一个新数组 
      
        像这样的函数不是纯函数,同样的输入不能得到同样的输出
        function demo(a) {
            return Math.random() + a
        }
      
        function demo1(a) { // 改写了参数的值
            a = 9
        }
      
        纯函数不会产生任何副作用,例如网络请求,输入和输出设备,不能调用Date.now(), Math.random()等不纯的方法
        ```
      
    • 3 store 将state,action, reducer联系到一起的对象

      通过store.getState() 可以得到状态

      通过store.dispatch(action对象) 可以更改状态,注意不是直接更改,其实每一个action对应一个reducer,最终是通过reducer来更改,需要注意的是redux只是在维护状态,在react中派发action导致转台改变,是不能引起页面的渲染的。因为redux只承诺维护状态,没承诺渲染页面,如果要渲染需要我们检测状态,手动去调用render. 注意手动调用不是this.render. 可以通过this.setState({}) 来重新渲染

      store.subscribe() 可以检测redux的状态,只要redux中的任意状态发生改变,指定的回调都会执行,因此页面一挂载就可以检测redux的状态了

      componentDidMount() {
      store.subscribe(() => {
      this.setState({})
      })
      }

      在组件中写可能写很多这样重复的代码,因此可以将检测的逻辑放在入口的index.js中,这样只要redux的状态一发生变化,真个App就会重新渲染,对应的子组件也会渲染。因为有diff算法的存在,不会引起大面积的重绘重排,因此不用担心性能问题。

react-redux

react-redux需要注意的几个点:

  • 所有的ui组件都应该包裹一个容器组件,他们是父子关系
  • 容器组件是真正和redux打交道的,里面可以随意使用redux的api
  • ui组件中不能使用任何redux的api
  • 容器组件会传给ui组件redux中所保存的状态,用于操作状态的方法。
  • 容器给ui传递状态,操作状态的方法均通过props传递
  • redux的状态变化并不会引起ui的更新,除非手动去检测状态变化。但是用了react-redux就不需要检测也能更新ui, 因为使用connect的时候他已经帮我们检测了。

容器组件就是一个桥梁,用于连接ui组件和redux,因此在容器组件中需要引入要包装的ui组件,要引入store(redux的核心就是store),需要注意的是容器组件不能亲自引入store,而是通过props的方式传入store,比如有一个容器组件Count,此时可以通过props传递
<Count store={store}/>
需要注意的是页面中不止这么一个容器组件,他都需要store,那么react-redux提供了一个批量提供store的方法
import {Provider} from 'react-redux';
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
)

需要引入连接的方式
import {connect} from 'react-redux'
// 得到一个容器组件
const ContainerComponent = connect()(ui组件);

容器组件和父子组件通信通过props的方式传递状态和操作状态的方法,正常的组件是通过标签属性的方式给子组件传递参数的,但是容器组件是由connect方法形成的,并没有和ui组件有这明确的父子关系,因此需要注意的是connect的第一个()需要两个参数。第一个参数是一个函数,用于生成传给ui组件的状态,需要返回一个对象,既然是操作状态,那么该函数一定能接受store中的状态,该函数接受一个参数state,第二个参数同样是一个函数,(当然也可以是一个对象,里面是一系列action,是精简版的写法,这这种写法,react-redux会自动分发对应的action),接受一个分发action的dispatch方法,返回一个对象,对象封装的是操作状态的方法。从语义上来讲,第一个参数就是一个mapStateToProps,第二个参数就是mapDispatchToProps

示例代码

funciton mapStateToProps(state) {
    return {
        count: state
    }
}

function mapDispatchToProps(dispatch) {
    return {
        increament: (number) =>  dispatch(createInreamentAction(number))
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(ui组件)

mapStateToProps映射状态 mapDispatchToProps映射操作状态的对象, 这两个函数都返回一个对象
mapDispatchToProps 也可以是一个对象,对象是一系列action,react-redux会自动分发这个action

注意事项:当一个ui组件对应一个容器组件的时候,如果这样编码会导致组件的数量成倍增加,可以同过一个文件将其整合,定义ui组件,最终以容器组件暴露

redux的开发工具

一个项目一般都由多个人写,可能都会用到redux存数据,但是彼此之间不知道状态是如何存的,都存了哪些状态,这时可以通过redux的开发工具来快速追踪状态的变化。需要引入一个库redux-devtools-extension
在store.js中引入

import {composeWithDevTools} from redux-devtools-extension

export default createStore(allReducers,composeWithDevTools(applyMiddleware(thunk)))


关于setState

setState更新状态的两种写法

  • setState(stateChange, [callbacnk]); // 对象式的写法,更改状态需要手动获取原来的state
    eg: this.setState({count: this.state.count+1})
  • setState(updater, [callback]); // 函数式的写法,不需要获取原来的state,因为会作为参数传入
    eg: this.setState((state, props) => { // 不仅能拿到state, 还可以拿到props
    return {count: state.count+1}
    })
    两种写法都有个可选的回调,因为react是异步更细的。需要注意的是setState是一个同步方法,由setState引起react更新状态是一个异步的操作,这个回调在状态更新完成并且在render后才调用的.

lazyLoad

路由组件的懒加载,不适用懒加载,所有的路由组件都会一次性被加载,如果有成百上千个路由组件,这是非常恐怖的。路由组件应该在跳那个路由就加载那个路由组件,这就是懒加载,在需要的时候才加载组件

hooks

  • React.useState(状态初始值)

    该方法返回一个数组,数组第一位是当前状态,第二位是更新状态的函数,因为数组的解构赋值是按下标来的,所以如下:

    let [count, setCount] = React.useState(0);

    需要注意的是每次调用setCount更新,函数组件都会执行,setCount的参数可以是一个函数,

  • React.useEffect(fn,[arr]) 可以在函数式组件里模拟生命周期钩子,fn就相当于一个声明周期钩子至于是哪一个需要看情况

    如果不指定第二个参数arr,那么所有的状态的改变都会执行回调fn。如果arr是空,表示全都不监测,如果不写第二个参数那么表示全部进行监测,如果要监听指定的状态,就需要在数组中指明。fn可以返回一个函数。

  • React.useRef()
    和createRef一样的作用

  • React.createContext

    1. 创建context容器对象
      const xxxContext = React.createContext();

    2. 渲染子组件时,外面包裹xxxContext.Provider,通过value属性给后代组件传递数据
      <xxxContext.Provider value={数据}>
      子组件
      </xxxContext.Provider>

    3)后代组件读取数据
    方式一,仅适用于类组件
    首先声明接收 static contextType = xxxContext 然后才能通过this.context.value拿到

      方式二,函数式组件和类组件都能接收到
      <xxxContext.Consumer>
          {
    
              value => ( // value就是context中的value数据
                  要显示的内容
              )
          }
    
      </xxxContext.Consumer>
    

    注意,在应用开发中一般不用context,一般都用它来封装react插件。

组件优化

- Component的两个问题
    1) 只要执行setState(), 即使不改变状态数据,组件也会重新render() ,也就是setState({}) 也会render.
    2) 只要当前组件重新render,就会自动重新render子组件 ,效率低。

  

    高效的做法应该是
        只有当前组件的state或者props数据发生改变时才重新render

    之所以有这样的问题是因为Component中的shouldComponentUpdate()默认总是返回true. 通过重写这个钩子可以解决这个问题

    shouldComponentUpdate(nextProps, nextState){
        
        console.log(this.props, this.state) // 当前的props和state
        console.log(nextProps, nextState); // 目标props和state
        // 根据当前数据和目标数据对比来决定返回ture|false ,至于怎么比有人做了,react中提供了PureComponet这个组件,他会重写 shouldComponentUpdate, 里面的对比逻辑是写好了的
        reuturn true;
    }

- PureComponent 

    该组件其实也没干啥,就是重写了shouldComponentUpdate, PureComponent也会有一点小瑕疵。因为他的底层进行了浅对比,因此如果是下面的这种写法同样会有问题

    const obj = this.state;
    obj.xxx = 'XXX'; // 改了某一个属性
    this.setState(obj); // 因为obj和state指向了同一个引用,因此在使用PureComponent比较时认为state是没有变化的,所以不会render.因此一定注意使用PureComponent,在更新状态时不要和原来的状态发生任何关系。使用时额外注意数组的那些方法。

renderProps

场景,比如有两个组件A,B,不应该关系不大,但是因为某些逻辑的原因可能需要这么写,

<A>
    <B/>
</A>
对于这种格式要个可以通过this.props.children来获取,但是有个问题如果B组件需要A组件内的数据是做不到的,因此就有了下面的这种格式

<A render={(parmas) => <B {...params}/>}/> // 就相当于传递了一个函数,该函数返回一个组件,函数名不一定叫render.

在A组件中预留一个位置this.props.render(可以传递A中的状态到B),类似于vue中插槽,

组件通信的总结

* 组件间的关系

    1) 父子组件
    2) 兄弟组件 (非嵌套组件)
    3) 祖孙组件(跨级组件)

* 几种通信方式

    1) props
        1.1) children props
        1.2) render props

    2) 消息的发布订阅
            pubsub ,event等
    3) 集中式管理如redux, dva等

    4) context:
            生产者和消费者模式

快速预览打包后的程序

全局安装serve,会快速开启一个服务。

错误边界

一个页面有多个组件构成,但是其中的某个组件因为某些不可控因素导致出错,此时整个页面都会出问题,边界错误就是处理这类问题的,就是当某个组件发生了错误,不要导致整个页面崩溃,而是将错误控制在最小的范围了,出错了给一个友好的提示。需要注意的是错误边界只有在生产环境有效,就是打包后才生效,开发环境是不生效的。总的来说错误边界就是用来捕获后代组件错误,渲染出备用页面,只能捕获后代组件生命周期产生的错误,不能捕获自己组件产生的错误和其他组件在合成事件,定时器中产生的错误。

当Parent的子组件出错时会走这个钩子,定义在父组件,并且携带错误信息err
state = {
    error: '' // 默认空,当发生了错误就会有值,可以根据这个值给一个友好的提示
}
static getDerivedFromError(err) {
    return {error: err}
}

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

推荐阅读更多精彩内容