共计 11263 个字符,预计需要花费 29 分钟才能阅读完成。
组件之间传值
-
父组件给子组件传值
在父组件中用标签属性的 = 模式传值
在子组件中应用 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 等。