知识点总结 REACT

1、react中如何创建一个组件

  ES6:class 组件名 extends Component{}

  ES5:var App=React.createClass({})

 

2、render函数什么时候会执行

  当this.state或者this.props发生改变的时候render函数执行

 

3、react中如何对state中的数据进行修改?setState为什么是异步的

  修改数据通过this.setState(参数一,参数二)

  this.setState是一个异步函数

    参数一:需要修改的数据,对象的形式

    参数二:修改成功的回调函数,这里相当于componentDidMount,可以获取到数据更新后的DOM结构

 

  this.setState中的第一个参数除了可以写成一个对象以外,还可以写成一个函数,函数中第一个值为prevState,第二个值为prePprops    this.setState((prevState,prop)=>{})

  

  为什么setState是异步的:

    当批量执行state的时候可以让DOM渲染的更快,也就是说多个setState在执行的过程中还需要被合并。

 

 4、react中如何定义自定义属性,以及限制外部数据的类型

  自定义属性:

    组件名.defaultProps={

      key:val

    }

 

  限制外部数据的类型:

    ①引入propTypes第三方模块

    ②类型限制

      组件名.propTypes={

        key:propTypes.类型

      }

 

 5、react路由常用的组件配置项

  BrowserRouter  路由的根组件,根组件下面只能有一个子元素

  HashRouter  路由的根组件,根组件下面只能有一个子元素

  withRouter

  Route  路由路径对应的文件

  Link  进行路由的跳转

  NavLink  进行路由的跳转,选中标签的时候NavLink会加上一个class

  Switch  被Switch包裹的Route渲染的时候只会渲染一个路径,建议:子页面不要放在Switch中,主页面放在Switch中

  Redirect  路由重定向

 

6、react路由中Route渲染组件的方法有哪几种?区别是什么

  ①<Route path="/home" component={组件名}></Route>

     通过component进行组件的渲染,这种方式的优点在于可以直接在组件的内部接收到history、location、match,缺点在于如果需要传参的组件,或者渲染jsx语法的时候无法使用。

  ②<Route path="/home" render={()=>{

     return <Home/>

   }}></Route>

     通过render进行渲染组件,优点在于可以进行组件传参,还可以渲染非组件的标签,缺点在于如果需要使用history、location、match的话需要在函数中传递过去。

 

7、如何控制路由路径的完全匹配

  给NavLink或Route设置exact属性

  

8、react中路由传参的方法有哪些

    //方案一:通过params进行传值
    <Router path="/one/:id" render={(history)=>{
        return <One history={history} />
    }}>
    </Router>
    //html跳转
    <NavLink to={"/one/"+1}>one</NavLink>
    //js跳转
    this.props.history.push("/one/"+"1")
    //接收值:在组件内部通过constructor接收
    constructor({history,location,match}){
        super();
        console.log(match.params)
    }

    //方案二:通过query进行传值
    <Router path="/one" render={(history)=>{
        return <One history={history} />
    }}></Router>
    //html跳转
    <NavLink to={
        pathname:"/one"
        query:{data:1}
    }>one</NavLink>
    //js跳转
    this.props.history.push({pathname:"/one",query:{data:1}})
    //获取值
    this.props.location.query.data
    注意:如果通过render进行渲染的时候需要在回调中将history的值传递过去,
如果是component进行渲染的话,只需要通过this.props进行接收

 

9、react中的编程式导航有哪些

  this.props.history.push("路径")  跳转路径

  this.props.history.back()  返回

  this.props.history.forward()  前进

  this.props.history.replace()  替换

 

10、react的生命周期

  组件创建的过程:

    constructor

    componentWillMount

    render

    componentDidMount

  当props中的数据发生改变后会执行哪些生命周期函数:

    componentWillReceiveProps

    shouldComponentUpdate

    componentWillUpdate

    render

    componentDidUpdate

  组件销毁的时候:

    componentWillUnmount

 

11、react中如何强制更新DOM

  this.foreUpdate()

 

12、谈谈对react中生命周期shouldComponentUpdate的理解

  shouldComponentUpdate是react性能优化非常重要的一环。组件接收新的state或者props时调用,我们设置在此对比前后两个props和state是否相同,如果相同则返回false阻止更新,因为相同的属性状态一定会产生相同的DOM树,这样就不需要创造新的DOM树和旧的DOM树进行diff算法对比,节省大量性能,尤其是在DOM结构复杂的时候。

 

13、谈谈你对虚拟DOM的理解,以及好处

  虚拟DOM:真实的js对象

  好处:虚拟DOM提高了react性能,每次更新数据后都会重新计算上虚拟DOM,并和上一次的虚拟DOM进行对比,对发生变化的部分进行批量更新。react中也提供了shouldComponentUpdate声明周期的回调,来减少数据变化后不必要的虚拟DOM对比过程,保证性能。

 

14、谈谈对flux的理解

  利用单项数据流的方式来组合react的视图组件,它是一种模式,而不是一种框架。

  flux可以帮我们解决非父子组件之间的传值

  flux数据传递流程 https://www.cnblogs.com/nanianqiming/p/9870194.html

  

 15、react17版本废除的生命周期,与新增的生命周期函数

  由于未来采用异步渲染机制,所以即将在17版本中去掉的生命周期钩子函数:

    componentWillMount

    componentWillReceiveProps

    componentWillUpdate

  新增的生命周期:

    static  getDeriveStateFromProps(nextProps,prevState){}

    用于替换componentWillReceiveProps,可以用来控制props更新state的过程,它返回一个对象表示新的state,如果不需要更新,返回null即可。在每次渲染之前都会调用,不管初始挂载还是后面的更新都会调用,这一点和componentWillReceiveProps(只有当父组件造成重新渲染时才调用)不同,每次都应该返回新对象。

    getSnapshotBeforeUpdate(){}  

    用于替换componentWillUpdate,该函数会在update后DOM更新前被调用,用于读取最新的DOM数据,返回值将作为componentDidUpdate的第三个参数,在最新的渲染数据提交给DOM前会立即调用,它让你在组件的数据可能要改变之前调用他们。

    componentDidCatch(error,info){}

    如果一个组件定义了componentDidCatch生命周期,则它将成为一个错误边界。错误边界会捕捉渲染期间,在生命周期中和在它们之下整棵树的构造函数中的错误,就像使用了try catch,不会将错误直接抛出了,保证应用的可能性。

 

16、this.setState之后做了哪些操作

  shouldComponentUpdate

  componentWillUpdate

  render

  componentDidUpdate

 

17、当组件的key值发生改变后会执行哪些生命周期函数

  componentWillUnmount

  constructor

  componentWillMount

  render

  componentDidMount

 

18、在react中是否封装过组件?封装组件要注意的地方

  常用封装组件用到的东西

    propTypes  限制外部数据的类型

    defaultProps  设置默认的外部数据

    父传子  子传父  context等传值方式

    高阶组件

  封装组价要注意组件的复用性、灵活性

 

19、如何接收组件内部的标签/内容

  this.props.children

 

20、说一下对redux的理解,以及使用的方式

  其实redux就是Flux的一种进阶实现,它是一个应用数据流框架,主要作用是应用状态的管理。

  redux的三大原则:

    ①单一的数据源

    ②state是只读的

    ③使用纯函数来进行修改

  redux中常用的三个方法:

    ①createStore()  创建store

    ②combineReducers()  合并多个reducer

    ③applyMiddleware()  使用中间件,处理异步的action

  redux数据传递的流程:

    当组件需要改变store的时候,需要创建一个action,然后通过dispatch(action)传递给store,然后store把action转发给reducers。reducers会拿到previousState(以前的state数据)和action。然后将previousState和action进行结合做新的数据(store)修改。然后生成一个新的数据传递给store。store通过触发subscribe方法来调用函数执行setState使得view的视图发生改变。

 

 21、请说下在react中如何处理异步的action

  通过applyMiddleware来使用中间件来处理action

  常用的中间件:

    redux-promise-middleware

    redux-thunk

    redux-saga

 

22、请说下对redux中间件的理解

  中间件:请求和回复之间的一个应用

  在redux中,中间件是dispatch和reducer之间的一个应用

 

23、请说下redux中你对reducers的理解,以及如何合并多个reducers

  在redux中reducer是一个纯函数,其中这个纯函数会接收2个参数,一个是state,一个是action。state用来保存公共的状态,state的特点是只能读不能修改。

  在实际开发中因为会涉及到多人协作开发,所以每个模块都有一个reducer,我们可以通过combineReducers来合并多个reducers。

 

24、请说下对高阶组件的理解,以及作用

  高阶组件:它是一个函数,接收一个组件作为参数,返回一个相对增强性的组件。

  高阶组件是一个函数,并不是组件。

  作用:

    ①属性代理----主要进行组件的复用(最常见的高阶组件的使用方式,通过做一些操作,将被包裹组件的props和新生成的props一起传递给此组件)

    ②反向继承----主要进行渲染的劫持(返回的react组件继承了被传入的组件,所以它能访问到的区域、权限更多,想比属性代理的方式,它更像是打入组件内部,对其进行修改)

 

25、在react中如何解决单页面开发首次加载白屏现象

  ①通过路由懒加载的方式  react-loadable

  ②首屏服务端渲染

 

26、请说下react中key值的理解

  react利用key来识别组件,它是一种身份标识,相同的key值react认为是同一个组件,这样后续相同的key对应的组件都不会被创建。

  有了key属性后,就可以与组件建立一种对应关系,react根据key来决定是销毁重新创建组件还是更新组件。

  key相同,若组件属性有所变化,则react只更新组件对应的属性,没有变化则不更新。

  key值不同,则react先销毁该组件(有状态组件的componentWillUnmount会执行),然后重新创建该组件(有状态组件的constructor和componentWIllUnmount都会执行)。

 

27、组件第一次执行的时候会执行哪些生命周期函数

  constructor

  componentWillMount

  render

  componentDidMount

  

28、哪些声明周期会执行多次

  render

  componentWillReceiveProps

  shouldComponentUpdate

  componentWillUpdate

  componentDidUpdate

 

29、当this.state和this.props执行的时候会执行哪些生命周期函数

  this.state

    shouldComponentUpdate

    componentWillUpdate

    render

    componentDidUpdate

  this.props

    componentWillReceiveProps

    shouldComponentUpdate

    render

    componentDidUpdate

  

30、谈谈对context的理解

  当不想在组件树中通过逐层传递props或state的方式来传递数据时,可以使用context来实现跨层级的组件数据传递,使用context可以实现跨组件传递。

  旧版context的基本使用:

    ①getChildContext根组件中声明,一个函数,返回一个对象,就是context

    ②childContextTypes根组件中声明,指定context的结构类型,如不指定会产生错误

    ③contextTypes子孙组件中声明,指定要接收的context的结构类型,可以只是context的一部分结构。contextTypes没有定义,context将是一个空对象。

    ④this.context在子孙组件中通过此来获取上下文

  新版context的使用:

    ①根组件中引入GlobalContext,并使用GlobalContext.Provider(生产者)

    ②组件引入GlobalContext并调用context,使用GlobalContext.Consumer

 

31、谈谈对react中withRouter的理解

  默认情况下必须是经过路由匹配渲染的组件在this.props上拥有路由参数,才能使用编程式导航的写法,withRouter是把不通过路由切换过来的组件,将react-router的history、location、match三个对象传入props对象上。

  简单来说就是:不是路由包裹的组件也可以使用路由的一些方法

 

32、说说对puerComponent的理解

  puerComponent表示一个纯组件,可以用来优化react程序,减少render函数渲染的次数,提高性能。

  puerComponent进行的是浅比较,也就是说如果是引用数据类型的数据,只会比较不是同一个地址,而不会比较这个地址里的数据是否一致。

  好处:当组件更新时,如果组件的props或state都没有改变,render函数就不会触发,省去虚拟DOM的生成和对比过程,达到提升性能的目的。具体原因是react自动帮我们做了一层浅比较。

 

33、react请求接口数据是在componentDidMount还是componentWillMount周期好

  如果你要获取外部数据并加载到组件上,只能在组件“已经”挂载到真是的网页上才能做这件事,其他情况你是加载不到组件的。componentDidMount方法中的代码,是在组件已经完全挂载到网页上才会调用被执行,所以保证数据的加载。

  react异步渲染开启的时候,componentWillMount就可能中途被打断,中断之后渲染又要重新做一遍,如果在componentWillMount中做ajax调用,代码里看到只有调用一次,但是实际上可能调用n多次,这个浪费了性能。如果把ajax放在componentDidMount中,因为componentDidMount在第二阶段,所以绝对不会多次重复调用,这里是ajax合适的位置。

   

 

34、react性能优化

  一、immutable简介

    Immutable Data是一旦创建,就不能修改的数据。对Immutable对象的任何修改或添加删除操作都会返回一个新的Immutable对象。Immutable实现的原理是Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变,同时为了避免deepCopy把所有的节点都复制一遍带来的性能损耗。

  在js中,引用类型的数据,优点在于频繁的操作数据都是在原对象的基础上修改,不会创建新对象,从而可以有效的利用内存,不会浪费内存,这种特性称为mutable(可变),但恰恰它的优点也是它的缺点,太过于灵活多变在复杂数据的场景下也造成了它的不可控性,假设一个对象在多处用到,在某一处不小心修改了数据,其他地方很难预见到数据是如何改变的,针对这种问题的解决方法,一般就像刚才的例子,会想复制一个新对象,再在新对象上做修改,这无疑会造成更多的性能问题以及内存浪费。

  为了解决这种问题,出现了immutable对象,每次修改immutable对象都会创建一个新的不可变对象,而老的对象不会改变。

 

  二、react中如何减少render函数渲染的次数

    在react中当this.state、this.props发生改变的时候render函数就会执行,但有些时候this.state、this.props没有发生改变的时候render函数也会执行。那么如何减少render函数的执行次数,可以封装一个BaseComponent来减少react中render函数的执行次数。

import React,{Component}from 'react';
import {is} from 'immutable';

class BaseComponent extends Component {
    shouldComponentUpdate(newProps, newState) {
        const thisProps = this.props || {};
        const thisState = this.state || {};
        newState = newState || {};
        newProps = newProps || {};

        if (Object.keys(thisProps).length !== Object.keys(newProps).length ||
            Object.keys(thisState).length !== Object.keys(newState).length) {
            return true;
        }

        for (const key in newProps) {
            if (!is(thisProps[key], newProps[key])) {
                return true;
            }
        }

        for (const key in newState) {
            if (!is(thisState[key], newState[key])) {
                return true;
            }
        }
        return false;
    }
}

export default BaseComponent;

     继承BaseComponent来创建开发中所需要的组件:

import BaseComponent from  "@common/BaseComponent";

export default class Home extends BaseComponent{
  constructor(){
    super()
  }
  ........
}

 

 35、react中key值的作用

  react中的key属性,它是一个特殊的属性,它的出现不是给开发者使用的,而是给react自己使用,有了key属性后,就可以与组件建立一种对应关系。react利用key来识别组件,它是一种身份标识,就像每个人都有身份证一样,每个key对应一个组件,相同的key react认为是同一个组件,这样后续相同的key对应的组件都不会被创建。

  key值相同:如果两个元素的key相同,且满足第一点元素类型相同,若元素属性有所变化,则react只更新组件对应的属性,这种情况下性能开销会相对较小。

  key值不相同:在render函数执行的时候,新旧两个虚拟DOM会进行对比,如果两个元素有不同的key,那么前后两次渲染中就会被认为是不同的元素,这时候旧的那个元素会被销毁,新的元素会被创建。

//更新前
render(){
    return(
        <List key="1"/>
    )
}
//更新后
render(){
    return(
        <List key="2"/>
    )
}

  例子:

  //tree1
  <ul>
      <li key="1">1</li>
      <li key="2">2</li>
  </ul>
  //tree2
  <ul>
      <li key="1">1</li>
      <li key="3">3</li>
      <li key="2">2</li>
  </ul>

  如果没有key值,react并不会执行插入操作,它会直接移除原先的第二个子元素,然后在append进去剩下的子元素,而其实我们这个操作只需要一个insert操作就能完成。为了解决这种问题,react需要我们提供一个key来帮助更新,减少性能开销。

  如果有key值,react就会通过key来发现剩下tree2的第二个子元素不是原先tree1的第二个元素,原先的第二个元素被挪到下面去了,因此在操作的时候就会直接指向insert操作,来减少DOM操作的性能开销。

  不推荐用属性中的index来做key值

    大部分情况下我们要在执行数据遍历的时候会用index来表示元素的key,这样做其实并不是很合理。我们用key的真实目的是为了标识前后两次渲染中元素的对应关系,防止发生不必要的更新操作。那么如果我们用index来标识key,数据在执行插入、排序等操作之后,原先的index并不再对应到原先的值,那么这个key就失去了本身的意义,还会带来其他问题。

  注意事项

    react中的key值必须保证其唯一和稳定性

    下面案例中的key值以Math.random()随机生成而定,这使得数组元素中的每项都重新销毁然后重新创建,有一定的性能开销

  {
      dataList.map((item,index)=>{
          return <div key={Math.random()}>{item.name}</div>
      })
  }

 

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

posted @ 2019-09-26 22:40  吴小明-  阅读(516)  评论(0编辑  收藏  举报