组件之间传值
父组件给子组件传值
在父组件中用标签属性的=模式传值
在子组件中应用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)
- class语法糖默认会帮你定义一个constructor,所以当你不须要应用constructor的时候,是能够不必本人定义的
- 当你本人定义一个constructor的时候,就肯定要写super(),否则拿不到this
- 当你在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等。