组件之间传值

  • 父组件给子组件传值

    在父组件中用标签属性的=模式传值

    在子组件中应用props来获取值

  • 子组件给父组件传值

    在组件中传递一个函数

    在子组件中用props来获取传递的函数,而后执行该函数

    在执行函数的时候把须要传递的值当成函数的实参进行传递

  • 兄弟组件之间传值

    利用父组件

    先把数据通过 【子组件】===》【父组件】

    而后在数据通过 【父组件】===〉【子组件】

    音讯订阅

    应用PubSubJs插件

React 16中新生命周期有哪些

对于 React16 开始利用的新生命周期: 能够看出,React16 自上而下地对生命周期做了另一种维度的解读:

  • Render 阶段:用于计算一些必要的状态信息。这个阶段可能会被 React 暂停,这一点和 React16 引入的 Fiber 架构(咱们前面会重点解说)是无关的;
  • Pre-commit阶段:所谓“commit”,这里指的是“更新真正的 DOM 节点”这个动作。所谓 Pre-commit,就是说我在这个阶段其实还并没有去更新实在的 DOM,不过 DOM 信息曾经是能够读取的了;
  • Commit 阶段:在这一步,React 会实现实在 DOM 的更新工作。Commit 阶段,咱们能够拿到实在 DOM(包含 refs)。

与此同时,新的生命周期在流程方面,依然遵循“挂载”、“更新”、“卸载”这三个狭义的划分形式。它们别离对应到:

  • 挂载过程:

    • constructor
    • getDerivedStateFromProps
    • render
    • componentDidMount
  • 更新过程:

    • getDerivedStateFromProps
    • shouldComponentUpdate
    • render
    • getSnapshotBeforeUpdate
    • componentDidUpdate
  • 卸载过程:

    • componentWillUnmount

Redux 怎么实现属性传递,介绍下原理

react-redux 数据传输∶ view-->action-->reducer-->store-->view。看下点击事件的数据是如何通过redux传到view上:

  • view 上的AddClick 事件通过mapDispatchToProps 把数据传到action ---> click:()=>dispatch(ADD)
  • action 的ADD 传到reducer上
  • reducer传到store上 const store = createStore(reducer);
  • store再通过 mapStateToProps 映射穿到view上text:State.text

代码示例∶

import React from 'react';import ReactDOM from 'react-dom';import { createStore } from 'redux';import { Provider, connect } from 'react-redux';class App extends React.Component{    render(){        let { text, click, clickR } = this.props;        return(            <div>                <div>数据:已有人{text}</div>                <div onClick={click}>加人</div>                <div onClick={clickR}>减人</div>            </div>        )    }}const initialState = {    text:5}const reducer = function(state,action){    switch(action.type){        case 'ADD':            return {text:state.text+1}        case 'REMOVE':            return {text:state.text-1}        default:            return initialState;    }}let ADD = {    type:'ADD'}let Remove = {    type:'REMOVE'}const store = createStore(reducer);let mapStateToProps = function (state){    return{        text:state.text    }}let mapDispatchToProps = function(dispatch){    return{        click:()=>dispatch(ADD),        clickR:()=>dispatch(Remove)    }}const App1 = connect(mapStateToProps,mapDispatchToProps)(App);ReactDOM.render(    <Provider store = {store}>        <App1></App1>    </Provider>,document.getElementById('root'))

React-Router怎么设置重定向?

应用<Redirect>组件实现路由的重定向:

<Switch>  <Redirect from='/users/:id' to='/users/profile/:id'/>  <Route path='/users/profile/:id' component={Profile}/></Switch>

当申请 /users/:id 被重定向去 '/users/profile/:id'

  • 属性 from: string:须要匹配的将要被重定向门路。
  • 属性 to: string:重定向的 URL 字符串
  • 属性 to: object:重定向的 location 对象
  • 属性 push: bool:若为真,重定向操作将会把新地址退出到拜访历史记录外面,并且无奈回退到后面的页面。

react代理原生事件为什么?

通过冒泡实现,为了对立治理,对更多浏览器有兼容成果

合成事件原理

如果react事件绑定在了实在DOM节点上,一个节点共事有多个事件时,页面的响应和内存的占用会受到很大的影响。因而SyntheticEvent作为中间层呈现了。

事件没有在指标对象上绑定,而是在document上监听所反对的所有事件,当事件产生并冒泡至document时,react将事件内容封装并叫由真正的处理函数运行。

版权申明:本文为CSDN博主「jiuwanli666」的原创文章,遵循CC 4.0 BY-SA版权协定,转载请附上原文出处链接及本申明。

对React SSR的了解

服务端渲染是数据与模版组成的html,即 HTML = 数据 + 模版。将组件或页面通过服务器生成html字符串,再发送到浏览器,最初将动态标记"混合"为客户端上齐全交互的应用程序。页面没应用服务渲染,当申请页面时,返回的body里为空,之后执行js将html构造注入到body里,联合css显示进去;

SSR的劣势:

  • 对SEO敌对
  • 所有的模版、图片等资源都存在服务器端
  • 一个html返回所有数据
  • 缩小HTTP申请
  • 响应快、用户体验好、首屏渲染快

1)更利于SEO

不同爬虫工作原理相似,只会爬取源码,不会执行网站的任何脚本应用了React或者其它MVVM框架之后,页面大多数DOM元素都是在客户端依据js动静生成,可供爬虫抓取剖析的内容大大减少。另外,浏览器爬虫不会期待咱们的数据实现之后再去抓取页面数据。服务端渲染返回给客户端的是曾经获取了异步数据并执行JavaScript脚本的最终HTML,网络爬中就能够抓取到残缺页面的信息。

2)更利于首屏渲染

首屏的渲染是node发送过去的html字符串,并不依赖于js文件了,这就会使用户更快的看到页面的内容。尤其是针对大型单页利用,打包后文件体积比拟大,一般客户端渲染加载所有所需文件工夫较长,首页就会有一个很长的白屏等待时间。

SSR的局限:

1)服务端压力较大

原本是通过客户端实现渲染,当初对立到服务端node服务去做。尤其是高并发拜访的状况,会大量占用服务端CPU资源;

2)开发条件受限

在服务端渲染中,只会执行到componentDidMount之前的生命周期钩子,因而我的项目援用的第三方的库也不可用其它生命周期钩子,这对援用库的抉择产生了很大的限度;

3)学习老本绝对较高 除了对webpack、MVVM框架要相熟,还须要把握node、 Koa2等相干技术。绝对于客户端渲染,我的项目构建、部署过程更加简单。

工夫耗时比拟:

1)数据申请

由服务端申请首屏数据,而不是客户端申请首屏数据,这是"快"的一个次要起因。服务端在内网进行申请,数据响应速度快。客户端在不同网络环境进行数据申请,且外网http申请开销大,导致时间差

  • 客户端数据申请
  • 服务端数据申请

    2)html渲染 服务端渲染是先向后端服务器申请数据,而后生成残缺首屏 html返回给浏览器;而客户端渲染是等js代码下载、加载、解析实现后再申请数据渲染,期待的过程页面是什么都没有的,就是用户看到的白屏。就是服务端渲染不须要期待js代码下载实现并申请数据,就能够返回一个已有残缺数据的首屏页面。

  • 非ssr html渲染
  • ssr html渲染

React组件命名举荐的形式是哪个?

通过援用而不是应用来命名组件displayName。

应用displayName命名组件:

export default React.createClass({  displayName: 'TodoApp',  // ...})

React举荐的办法:

export default class TodoApp extends React.Component {  // ...}

参考:前端react面试题具体解答
**

React 与 Vue 的 diff 算法有何不同?

diff 算法是指生成更新补丁的形式,次要利用于虚构 DOM 树变动后,更新实在 DOM。所以 diff 算法肯定存在这样一个过程:触发更新 → 生成补丁 → 利用补丁。

React 的 diff 算法,触发更新的机会次要在 state 变动与 hooks 调用之后。此时触发虚构 DOM 树变更遍历,采纳了深度优先遍历算法。但传统的遍历形式,效率较低。为了优化效率,应用了分治的形式。将繁多节点比对转化为了 3 种类型节点的比对,别离是树、组件及元素,以此晋升效率。

  • 树比对:因为网页视图中较少有跨层级节点挪动,两株虚构 DOM 树只对同一档次的节点进行比拟。
  • 组件比对:如果组件是同一类型,则进行树比对,如果不是,则间接放入到补丁中。
  • 元素比对:次要产生在同层级中,通过标记节点操作生成补丁,节点操作对应实在的 DOM 剪裁操作。

以上是经典的 React diff 算法内容。自 React 16 起,引入了 Fiber 架构。为了使整个更新过程可随时暂停复原,节点与树别离采纳了 FiberNode 与 FiberTree 进行重构。fiberNode 应用了双链表的构造,能够间接找到兄弟节点与子节点。整个更新过程由 current 与 workInProgress 两株树双缓冲实现。workInProgress 更新实现后,再通过批改 current 相干指针指向新节点。

Vue 的整体 diff 策略与 React 对齐,尽管不足工夫切片能力,但这并不意味着 Vue 的性能更差,因为在 Vue 3 初期引入过,前期因为收益不高移除掉了。除了高帧率动画,在 Vue 中其余的场景简直都能够应用防抖和节流去进步响应性能。

constructor

答案是:在 constructor 函数外面,须要用到props的值的时候,就须要调用 super(props)
  1. class语法糖默认会帮你定义一个constructor,所以当你不须要应用constructor的时候,是能够不必本人定义的
  2. 当你本人定义一个constructor的时候,就肯定要写super(),否则拿不到this
  3. 当你在constructor外面想要应用props的值,就须要传入props这个参数给super,调用super(props),否则只须要写super()

React.Children.map和js的map有什么区别?

JavaScript中的map不会对为null或者undefined的数据进行解决,而React.Children.map中的map能够解决React.Children为null或者undefined的状况。

React如何获取组件对应的DOM元素?

能够用ref来获取某个子节点的实例,而后通过以后class组件实例的一些特定属性来间接获取子节点实例。ref有三种实现办法:

  • 字符串格局:字符串格局,这是React16版本之前用得最多的,例如:<p ref="info">span</p>
  • 函数格局:ref对应一个办法,该办法有一个参数,也就是对应的节点实例,例如:<p ref={ele => this.info = ele}></p>
  • createRef办法:React 16提供的一个API,应用React.createRef()来实现       

何为 reducer

一个 reducer 是一个纯函数,该函数以先前的 state 和一个 action 作为参数,并返回下一个 state。

对React-Fiber的了解,它解决了什么问题?

React V15 在渲染时,会递归比对 VirtualDOM 树,找出须要变动的节点,而后同步更新它们, 零打碎敲。这个过程期间, React 会占据浏览器资源,这会导致用户触发的事件得不到响应,并且会导致掉帧,导致用户感觉到卡顿

为了给用户制作一种利用很快的“假象”,不能让一个工作长期霸占着资源。 能够将浏览器的渲染、布局、绘制、资源加载(例如 HTML 解析)、事件响应、脚本执行视作操作系统的“过程”,须要通过某些调度策略正当地调配 CPU 资源,从而进步浏览器的用户响应速率, 同时兼顾工作执行效率。

所以 React 通过Fiber 架构,让这个执行过程变成可被中断。“适时”地让出 CPU 执行权,除了能够让浏览器及时地响应用户的交互,还有其余益处:

  • 分批延时对DOM进行操作,防止一次性操作大量 DOM 节点,能够失去更好的用户体验;
  • 给浏览器一点喘息的机会,它会对代码进行编译优化(JIT)及进行热代码优化,或者对 reflow 进行修改。

核心思想: Fiber 也称协程或者纤程。它和线程并不一样,协程自身是没有并发或者并行能力的(须要配合线程),它只是一种管制流程的让出机制。让出 CPU 的执行权,让 CPU 能在这段时间执行其余的操作。渲染的过程能够被中断,能够将控制权交回浏览器,让位给高优先级的工作,浏览器闲暇后再复原渲染。

React中constructor和getInitialState的区别?

两者都是用来初始化state的。前者是ES6中的语法,后者是ES5中的语法,新版本的React中曾经废除了该办法。

getInitialState是ES5中的办法,如果应用createClass办法创立一个Component组件,能够主动调用它的getInitialState办法来获取初始化的State对象,

var APP = React.creatClass ({  getInitialState() {    return {         userName: 'hi',        userId: 0     }; }})

React在ES6的实现中去掉了getInitialState这个hook函数,规定state在constructor中实现,如下:

Class App extends React.Component{    constructor(props){      super(props);      this.state={};    }  }

state 是怎么注入到组件的,从 reducer 到组件经验了什么样的过程

通过connect和mapStateToProps将state注入到组件中:

import { connect } from 'react-redux'import { setVisibilityFilter } from '@/reducers/Todo/actions'import Link from '@/containers/Todo/components/Link'const mapStateToProps = (state, ownProps) => ({    active: ownProps.filter === state.visibilityFilter})const mapDispatchToProps = (dispatch, ownProps) => ({    setFilter: () => {        dispatch(setVisibilityFilter(ownProps.filter))    }})export default connect(    mapStateToProps,    mapDispatchToProps)(Link)

下面代码中,active就是注入到Link组件中的状态。 mapStateToProps(state,ownProps)中带有两个参数,含意是∶

  • state-store治理的全局状态对象,所有都组件状态数据都存储在该对象中。
  • ownProps 组件通过props传入的参数。

reducer 到组件经验的过程:

  • reducer对action对象解决,更新组件状态,并将新的状态值返回store。
  • 通过connect(mapStateToProps,mapDispatchToProps)(Component)对组件 Component进行降级,此时将状态值从store取出并作为props参数传递到组件。

高阶组件实现源码∶

import React from 'react'import PropTypes from 'prop-types'// 高阶组件 contect export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => {    class Connect extends React.Component {        // 通过对context调用获取store        static contextTypes = {            store: PropTypes.object        }        constructor() {            super()            this.state = {                allProps: {}            }        }        // 第一遍需初始化所有组件初始状态        componentWillMount() {            const store = this.context.store            this._updateProps()            store.subscribe(() => this._updateProps()); // 退出_updateProps()至store里的监听事件列表        }        // 执行action后更新props,使组件能够更新至最新状态(相似于setState)        _updateProps() {            const store = this.context.store;            let stateProps = mapStateToProps ?                mapStateToProps(store.getState(), this.props) : {} // 避免 mapStateToProps 没有传入            let dispatchProps = mapDispatchToProps ?                mapDispatchToProps(store.dispatch, this.props) : {                                    dispatch: store.dispatch                                } // 避免 mapDispatchToProps 没有传入            this.setState({                allProps: {                    ...stateProps,                    ...dispatchProps,                    ...this.props                }            })        }        render() {            return <WrappedComponent {...this.state.allProps} />        }    }    return Connect}

对componentWillReceiveProps 的了解

该办法当props发生变化时执行,初始化render时不执行,在这个回调函数外面,你能够依据属性的变动,通过调用this.setState()来更新你的组件状态,旧的属性还是能够通过this.props来获取,这里调用更新状态是平安的,并不会触发额定的render调用。

应用益处: 在这个生命周期中,能够在子组件的render函数执行前获取新的props,从而更新子组件本人的state。 能够将数据申请放在这里进行执行,须要传的参数则从componentWillReceiveProps(nextProps)中获取。而不用将所有的申请都放在父组件中。于是该申请只会在该组件渲染时才会收回,从而加重申请累赘。

componentWillReceiveProps在初始化render的时候不会执行,它会在Component承受到新的状态(Props)时被触发,个别用于父组件状态更新时子组件的从新渲染。

React 16.X 中 props 扭转后在哪个生命周期中解决

在getDerivedStateFromProps中进行解决。

这个生命周期函数是为了代替componentWillReceiveProps存在的,所以在须要应用componentWillReceiveProps时,就能够思考应用getDerivedStateFromProps来进行代替。

两者的参数是不雷同的,而getDerivedStateFromProps是一个动态函数,也就是这个函数不能通过this拜访到class的属性,也并不举荐间接拜访属性。而是应该通过参数提供的nextProps以及prevState来进行判断,依据新传入的props来映射到state。

须要留神的是,如果props传入的内容不须要影响到你的state,那么就须要返回一个null,这个返回值是必须的,所以尽量将其写到函数的开端:

static getDerivedStateFromProps(nextProps, prevState) {    const {type} = nextProps;    // 当传入的type发生变化的时候,更新state    if (type !== prevState.type) {        return {            type,        };    }    // 否则,对于state不进行任何操作    return null;}

什么是上下文Context

Context 通过组件树提供了一个传递数据的办法,从而防止了在每一个层级手动的传递 props 属性。

  • 用法:在父组件上定义getChildContext办法,返回一个对象,而后它的子组件就能够通过this.context属性来获取
import React,{Component} from 'react';import ReactDOM from 'react-dom';import PropTypes from 'prop-types';class Header extends Component{    render() {        return (            <div>                <Title/>            </div>        )    }}class Title extends Component{    static contextTypes={        color:PropTypes.string    }    render() {        return (            <div style={{color:this.context.color}}>                Title            </div>        )    }}class Main extends Component{    render() {        return (            <div>                <Content>                </Content>            </div>        )    }}class Content extends Component{    static contextTypes={        color: PropTypes.string,        changeColor:PropTypes.func    }    render() {        return (            <div style={{color:this.context.color}}>                Content                <button onClick={()=>this.context.changeColor('green')}>绿色</button>                <button onClick={()=>this.context.changeColor('orange')}>橙色</button>            </div>        )    }}class Page extends Component{    constructor() {        super();        this.state={color:'red'};    }    static childContextTypes={        color: PropTypes.string,        changeColor:PropTypes.func    }    getChildContext() {        return {            color: this.state.color,            changeColor:(color)=>{                this.setState({color})            }        }    }    render() {        return (            <div>                <Header/>                <Main/>            </div>        )    }}ReactDOM.render(<Page/>,document.querySelector('#root'));

Redux 中间件是怎么拿到store 和 action? 而后怎么解决?

redux中间件实质就是一个函数柯里化。redux applyMiddleware Api 源码中每个middleware 承受2个参数, Store 的getState 函数和dispatch 函数,别离取得store和action,最终返回一个函数。该函数会被传入 next 的下一个 middleware 的 dispatch 办法,并返回一个接管 action 的新函数,这个函数能够间接调用 next(action),或者在其余须要的时刻调用,甚至基本不去调用它。调用链中最初一个 middleware 会承受实在的 store的 dispatch 办法作为 next 参数,并借此完结调用链。所以,middleware 的函数签名是({ getState,dispatch })=> next => action。

对虚构 DOM 的了解?虚构 DOM 次要做了什么?虚构 DOM 自身是什么?

从实质上来说,Virtual Dom是一个JavaScript对象,通过对象的形式来示意DOM构造。将页面的状态形象为JS对象的模式,配合不同的渲染工具,使跨平台渲染成为可能。通过事务处理机制,将屡次DOM批改的后果一次性的更新到页面上,从而无效的缩小页面渲染的次数,缩小批改DOM的重绘重排次数,进步渲染性能。

虚构DOM是对DOM的形象,这个对象是更加轻量级的对DOM的形容。它设计的最后目标,就是更好的跨平台,比方node.js就没有DOM,如果想实现SSR,那么一个形式就是借助虚构dom,因为虚构dom自身是js对象。 在代码渲染到页面之前,vue或者react会把代码转换成一个对象(虚构DOM)。以对象的模式来形容实在dom构造,最终渲染到页面。在每次数据发生变化前,虚构dom都会缓存一份,变动之时,当初的虚构dom会与缓存的虚构dom进行比拟。在vue或者react外部封装了diff算法,通过这个算法来进行比拟,渲染时批改扭转的变动,原先没有产生扭转的通过原先的数据进行渲染。

另外古代前端框架的一个根本要求就是毋庸手动操作DOM,一方面是因为手动操作DOM无奈保障程序性能,多人合作的我的项目中如果review不严格,可能会有开发者写出性能较低的代码,另一方面更重要的是省略手动DOM操作能够大大提高开发效率。

为什么要用 Virtual DOM:

(1)保障性能上限,在不进行手动优化的状况下,提供过得去的性能

上面比照一下批改DOM时实在DOM操作和Virtual DOM的过程,来看一下它们重排重绘的性能耗费∶

  • 实在DOM∶ 生成HTML字符串+ 重建所有的DOM元素
  • Virtual DOM∶ 生成vNode+ DOMDiff+必要的DOM更新

Virtual DOM的更新DOM的筹备工作消耗更多的工夫,也就是JS层面,相比于更多的DOM操作它的生产是极其便宜的。尤雨溪在社区论坛中说道∶ 框架给你的保障是,你不须要手动优化的状况下,我仍然能够给你提供过得去的性能。 (2)跨平台 Virtual DOM实质上是JavaScript的对象,它能够很不便的跨平台操作,比方服务端渲染、uniapp等。