太阳集团城8722(中国·Macau)有限公司-Official website

掌握太阳集团城8722最新动态了解行业最新趋势
API接口,开发服务,免费咨询服务

关于 react 那些小知识点

说在前面

关于 react 的总结过去半年就一直碎碎念着要搞起来,各(wo)种(tai)原(lan)因(le),没错就是我太懒了。上个月去体检的时候,查体检报告时都顶着各种心理压力呢, 和想象中的一样各种职业病各种身体亚健康呢。 所以现在尽量早睡坚持早起了,然后呢,起得早就有时间做点儿总结了。心心念的东西重新拿了起来了。希望这个总结归纳能对你的日常开发或者跳槽面试有帮助哪怕只有那么一点点,反正对我帮助是挺大,温故而知新嘛!!!

废话说了一堆, 这个总结可能大概也许会以问答的形式总结
希望你能各个击破,像闯关卡一样一个一个过!开始吧 !Let's go!

【1】react component有几种写法?分别是什么?

① 函数式定义的无状态组件(Stateless Functional)

  • 性能更高效、代码更简洁
  • 没有 state,也就是无状态
  • 不需要管理/维护 组件的生命周期
  • 纯函数,相同的 props 会得到同样的UI渲染结果
    function List (props) {
        return <div>我是一个函数式定义的react组件div>
    }

② ES5方式 React.createClass 定义的组件(该方式已经被废弃,官方文档推荐是用①和③)
③ ES6 方式定义的组件(Class Components)

    class List extends React.Component {
        render() {
            return <div>我是一个es6方式定义的react组件div>
        }
    }

官方文档写的还是颇具神秘感的,先告诉我们①和③方式在 UI 渲染效果是一毛一样的,但是'Classes have some additional features...' Class 这种方式比 Functional 这种方式多了些不一样的地方。那么问题来了。多了哪些不一样的呢? 不一样的地方你可能也发现了,有无 state有无生命周期...等

【2】那什么时候该用 Stateless Functional 什么时候用 Class 呢?

推荐使用 Functional,能用 Functional 就用 Functional,就酱。
多说一句。Class 是用来创建包含状态生命周期用户交互的复杂组件,而当组件只是用来纯展示或者 props 传递渲染时(展示性),二话不说请用 Stateless Functional 来快速创建组件。

【3】无状态组件(Stateless Functional)有哪些优缺点

  • 优点
  1. 语法/代码更加简洁
  2. 占用内存小(没有 props 等属性), 首次 render 性能更好
  3. 不需要管理/维护组件的生命周期
  4. 纯函数,相同的 props 会得到同样的 UI 渲染结果
  5. 单元测试更容易进行。因为逻辑都被移出了 view 层,所以单元测试时不需要渲染任何东西,可以专注于单个逻辑。
  • 缺点
  1. 无生命周期函数。对于一个函数而言应该是谈不上生命周期。当然了,我们其实可以使用高阶组件去实现生命周期。
  2. 没有 this。在Stateless中 this 是 undefined 。

【4】React.Component 绑定方法的几种方法?

    //第一种方法:构造函数中绑定
    
    class List extends React.Component {
        constructor(props) {
            super(props)
            this.onClickList = this.onClickList.bind(this)
        }
        
        onClickList() {
            console.log('我被点了')
        }
        
        render() {
            return <div onClick={this.onClickList}>点我点我点我div>
        }
        
    }
    
    //第二种方法: 在render()行内事件使用bind来绑定
    
    class List extends React.Component {
        
        onClickList() {
            console.log('我被点了')
        }
        
        render() {
            return <div onClick={this.onClickList.bind(this)}>点我点我点我div>
        }
        
    }
    
    //第三种方法: 使用箭头函数 => 
    
    class List extends React.Component {
        
        onClickList = () => {
            console.log('我被点了')
        }
        
        render() {
            return <div onClick={this.onClickList}>点我点我点我div>
        }
        
    }
    
    //第四种,当然,你要在render()行内使用箭头函数也行
    
    class List extends React.Component {
        
        onClickList() {
            console.log('我被点了')
        }
        
        render() {
            return <div onClick={() => this.onClickList()}>点我点我点我div>
        }
        
    }

我日常开发都比较喜欢用箭头函数的方法,就因为偷懒,代码量比第一种少。当然,官方说在 render 中创建函数(第二,和第四种)可能会有性能问题。但往往需要传递参数或者回调时,都得用到。例如:

    

【5】智能组件 vs 木偶组件 ? 或者 容器组件 vs 展示组件 ?

Smart 组件 和 Dumb 组件对于开发过 react 项目的朋友来说应该不陌生了。

Dumb 组件,听名字你就知道这种组件很傻很木,因为木偶组件只关心一件事情就是 —— 根据 props 进行渲染。
Smart 组件就很聪明,它专门做数据相关的逻辑,和各路数据打交道,ajax获取数据,定义好数据操作的相关函数,然后将这些数据、函数直接传递给具体实现的组件(Dumb 组件)即可。所以根据是否需要高度的复用性,把组件划分为 Dumb 和 Smart 组件。

小提示1:Smart 组件复用性不强甚至不需要复用,Dumb 组件往往是复用性强的,但是Dumb 组件对于 Smart 组件的带入性不要太强,因为带入太多逻辑会导致复用性降低。二者选择,设计组件时需要斟酌一下。

小提示2:Dumb 组件 的子组件也应该是 Dumb 组件。

关于React生命周期

关于生命周期,面试的时候总喜欢问点儿相关的,而且想要了解别人写的 react 代码,深刻理解 react 生命周期也是很重要的。先不要往下看,闭上眼睛想想看你所了解的 react 生命周期有哪些?

...

...

...

...

...

...

liftcycle.jpg

ok 你应该想完了哈。是不是大概有下面这么一个流程?(图片是经典的组件挂载图来源于网络)

react 组件的生命周期方法都可以被分割成四个阶段:初始化、挂载阶段(Mounting)、更新阶段(Updating)、卸载阶段(Unmounting)。

接下来就让我们去看看生命周期都有哪些小知识点。

【6】Mounting(挂载) -- 下面这些方法将会在 component 实例被创建和插入到DOM后调用。

  • constructor()
  • componentWillMount()
  • render()
  • componentDidMount()

【7】Updating -- props 或者 state 的变化都会导致更新。下面这些方法会在 component 重新渲染时调用。

  • componentWillReceiveProps()
  • shouldComponentUpdate()
  • componentWillUpdate()
  • render()
  • componentDidUpdate()

【8】Unmounting -- 该方法将会在 component 从DOM中移除时调用。

  • componentWillUnmount()

接下来简单的介绍一下几个生命周期。

【9】1. componentWillMount

componentWillMout() 是在组件挂载(mount)之前被调用.
componentWillMount()是唯一一个在服务器端渲染(ssr)调用的生命周期钩子

关于 setState 在 componentWillMount 使用:可以使用。因为它是 render 方法之前被调用,因此 setState 也不会导致重绘(re-render)

【10】2. componentDidMount

componentDidMount() 在组件挂载之后立即执行

在这个钩子里合适:

  • ajax 请求
  • 初始化DOM节点的操作
  • 设置计时器 setTimeout 或者 setInterval (温馨提示,别忘了在 componentWillUnmount 关闭这些计时器)

关于 setState 在 componentDidMount 使用: 可以使用。但是经常导致性能问题。当然非要在 render 前拿到 DOM 节点的大小和位置,是可以用的。

插曲。面试题:ajax 请求应该在哪个生命周期?为什么?

【11】3. componentWillReceiveProps(nextProps)

componentWillReceiveProps 将会在已挂载组件(mounted component)接收到新的 props 之前调用。所以初始化 props 的mount不会触发这个函数。直接 setState不会触发这个函数。

在这个钩子里合适:

  • 更新 state 的值(比如重置)
  • 比较 this.props 和 nextProps

特别特别特别要注意的是,当父组件导致该组件 re-render 时,即便 props 没有发生任何的改变,react 也有可能执行该钩子函数。所以呢,所以就是如果你想要真正处理 props 的变化,要记得比较当前 props 和 nextProps.

关于setState在componentWillReceiveProps使用: 可以使用

【12】4. shouldComponentUpdate(nextProps, nextState)

当改变state 或者 props 并且是在render之前会调用shouldComponentUpdate,说白了就是该钩子函数用于告诉 React 组件是否需要重新渲染。

shouldComponentUpdate 默认return true,如果return false componentWillUpdaterendercomponentDidUpdate都将不会被调用。千万记住一点, 当return false时,当他们的 state 发生改变时,并不会阻止子组件(child component)进行重新渲染。

shouldComponentUpdate在两种情况下不会被调用:

  • 组件初始化
  • 使用forceUpdate的情况

大家应该都是 shouldComponentUpdate 还有一个知识点就是和 react 组件性能优化相关的。是的。你可以this.state 和 nextState、this.props 和 nextProps 做比较来决定出 return false 并告诉 react 可以不更新该组件。如果做的只是一些浅层的数据比较完全可以用 PureComponent 来代替(深层的嵌套数据PureComponent也无能为力)

react 不建议在 shouldComponentUpdate 做深层的对比或者用 JSON.stringify(),因为这样反而损害到性能。

【13】5. componentWillUpdate(nextProps, nextState)

state 或者 props 更新后 re-render 之前调用。

注意:不要在componentWillUpdate 使用 this.setState, 或者 redux 分发一个action(dispatch a Redux action),因为在 componentWillUpdate 之前会触发组件的更新。 如果非要在做以上操作的话,可以在componentWillReceiveProps 哦

【14】6. componentDidUpdate(prevProps, prevState)

在组件更新之后马上调用 componentDidUpdate。

在这个钩子函数中你可以:

  • 操作 DOM
  • 发起网络请求

【15】7. componentWillUnmount

在组件卸载(unmounted)和销毁(destroyed)前调用。

在componentWillUnmount你可以执行任何需要清除的方法。比如:

  • 清除计时器
  • 断开网络请求
  • 解绑dom事件
  • 等等

【16】生命周期table

生命周期是否可以调用this.setState初始化是否执行
componentWillMount可以
componentDidMount可以
componentWillReceiveProps可以
shouldComponentUpdate不可以
componentWillUpdate不可以
componentDidUpdate可以
componentWillUnmount不可以

特别特别特别注意:
①componentWillMount 和 componentWillReceiveProps 调用 setState 不会重复渲染(re-render)
②componentDidUpdate,不能直接 this.setState, 不然会溢出栈。需要对 prevProps 与 this.props 和 prevState 和 this.state 做一个判断再执行 this.setState。就类似while循环不能陷入死循环。

好吧。长篇大论了一番 react 的生命周期。不为什么,就因为它非常的重要。不管是对你的面试或者日常开发或者阅读理解别人的代码都是非常重要。哪个阶段会触发哪个生命周期,哪个能干什么哪个不能干什么,哪个更合适哪个不合适。来!干了它,咱们再继续往下看!

......
.....
....
...
..
.
感谢你能看到这里,咱们继续往下凿....
.
..
...
....
.....
......

【17】props 和 state 的区别

  1. "props"是别人的, props实现组件间的状态传递,props从父组件到子组建的数据传递;"state"是自己的,state只能定义在组件内部,定义组件的自己的状态。
  2. props 是不可变的; state 可以通过this.setState改变

【18】props vs state

?propsstate
可以从父组件获得初始值吗?YesYes
可以被父组件改变吗?YesNo
内部(当前)组件可以设置默认值吗?YesYes
可以改变内部(当前)组件吗?NoYes
可以为子组件设置初始值吗?YesYes
可以改变子组件吗?YesNo

【19】jsx是什么?

刚接触 react 的童鞋,看到 jsx,第一反应就是“丑”。说实在的一开始写 jsx 我也是拒绝的,但是没想到 jsx 其语法和背后的逻辑让构建react组件变得极其简单。
那 jsx 到底是什么呢?jsx 是一个看起来很像 XML 的 JavaScript 语法扩展。说白了 jsx 并不是什么高深的技术,可以说只是一个比较高级但很直观的语法糖。它非常有用,却不是一个必需品,没有 jsx 的 React 也可以正常工作:只要你乐意用 JavaScript 代码去创建这些虚拟 DOM 元素(但是真的超级麻烦)。

jsx优点:

  • 执行更快,因为它在编译为 JavaScript 代码后进行了优化
  • 它是类型安全的,在编译过程中就能发现错误
  • 编写模板更加简单快速
  • 更加直观,可读性高

来看看以下代码:
1.当我们用HTML描述一个按钮的时候,你会发现一个 DOM 元素包含的信息其实只有三个:标签名,属性,子元素

    <div id="btn-wrap">
        <button class="btn">clickbutton>
    div>

2.我们如果用js描述,可以通过JSON对象,且依然包括元素的标签名、属性,子元素

    {
        type: 'div',
        props: { id: 'btn-wrap' },
        children: {
            type: 'button',
            props: { className: 'btn' },
            children: 'click'
        }
    }

仔细观察,你会发现HTML和js描述一个按钮他们所对应的结构简直是一毛一样的,就是说一个html构建的UI界面我们完全可以用js来描述。你会发现HTML书写一个按钮远比js书写方式来得苏胡,而且结构更加清晰。但是如果 你坚决要用js来写我也不会反对的。来!先写个div十层嵌套试试?

react提供jsx语法糖,将html语法直接加入到JavaScript代码中去,再通过编译器(babel)转化为JavaScript后由浏览器执行。

我们修改src/index.js的代码如下

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class HappyReact extends Component {
  render() {
    return (
        <div>
            <h1 id="title">happy react !h1>
        div>
    )
  }
}

ReactDOM.render(<HappyReact />, document.getElementById('root'));

这时候你会看到页面浏览器自动刷新了且页面显示了'happy react !'字样。

如果以上代码经过编译会变成:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class HappyReact extends Component {
  render() {
    return (
      React.createElement(
        'div',
        null,
        React.createElement(
            'h1',
            { id: 'title' },
            'happy react !'
        )
      )
    )
  }
}

ReactDOM.render(
    React.createElement(
        HappyReact,
        null
    ),
    document.getElementById('root')
);

编译前后两段代码渲染结果是一样的,你一定发现了jsx的代码更加直观便于维护了吧!

虽然你看到的html写在了js代码中,但是你永远要记住"jsx最终其实就是JavaScript对象"。react通这个对象来创建或者更新虚拟元素最终来管理virtual DOM(虚拟DOM)

jsx对象元素可以理解为和真实元素一一对应的,它的创建、更新、删除都是在内存中完成的。并不会直接渲染到真实DOM中去,整个react应用程序唯一操作到DOM就是:

    ReactDOM.render(, document.getElementById('root'));

【20】大概知道jsx是什么了。我们是得花点儿时间学习/了解/回忆一下jsx的写法。

  1. render函数只能return一个根节点,只允许被一个标签包裹
  2. Component 命名首字大写,HTML 标签用小写
  3. 如果不存在子节点,可以使用自闭合
  4. jsx的注释 {/* */}
  5. JavaScript 属性表达式,属性值用 {}
  6. 三元表达式
  7. 数组递归(渲染列表) map
  8. 两个特殊属性 class, for. 因为class, for在JavaScript中这个两个单词都是关键词。因此需要做一手转换。其他属性可以像写html一样添加上去。
  9. jsx书写样式
  10. 事件处理,使用inline方式的驼峰式写法,例如onClick、onChange
  11. HTML转义 --> dangerouslySetInnerHTML={{__html: '
    hhh
    '}}
  12. 利用es6 中 ... 展开运算符。例如
    const helloProps = {
        value: 'hello',
        show: true,
    }
 
  1. 如果属性值是true 这里直接写属性名。例如
    <Button disabled={true} /> 
    可以写成
    <Button disabled /> 
  1. false, null, undefined, true 是有效的子内容,但是不会被渲染出来。以下表达式渲染结果是一样的:
    <div />
    <div>div>
    <div>{false}div>
    <div>{null}div>
    <div>{undefined}div>
    <div>{true}div>

15 ...

...好吧我可能暂时想到这么多了。

【21】refs 是什么?(refs功能,如何实现?)

react 提供了一种特殊属性, 允许您直接访问DOM元素或组件实例。
ref 可以返回一个字符串(string) 或者 一个回调函数(cb),这个回调函数会在组件实例化或者销毁之后立即执行。

字符串refs在未来的版本中可能被移除,所以推荐回调的方式来代替。

    class TextInput extends Component {
        componentDidMount() {
            this.textInput.focus()
        }
        
        render() {
            return (
                <input ref={(input) => this.textInpuf = input} />
            )
        }
    }

官方推荐几种很好的方式使用refs:

  • 管理焦点,文本选择或者媒体播放
  • 触发重要的动画
  • 整合第三方DOM库

当然能不用refs就尽量不要用refs,不要太过度依赖refs来解决问题。

【22】什么是受控组件和什么是非受控组件

在react表单组件可被分为两类:受控组件 和 非受控组件。

  • 受控组件
    我们简单的理解,设置了 value 的 (表单标签) 是一个受控组件。
    当我们设置了value为"hi"(某个值)时,且在页面上渲染出改值时,我们在渲染出来的元素里输入任何值都不起作用。因为react 已经把value赋值为"hi"。 要想改变value值,还必须配合这onChange 和 setState 来实现。

当然你也可以看看官网文档来如何定义受控组件的。

在 HTML 中,表单元素如