事件
- event 是syntheticEvent ,react模拟出来dom事件所有能力
- event.nativeEvent是原生事件
- 所有的事件,都被挂载到document上
- 和dom事件不一样,和Vue也不一样
事件传参,最后都会追加一个参数,即可接收event
bind this
关于event参数
传递自定义参数
受控组件
表单 相当于vue中v-model
非受控组件
假设我们现在有一个表单,表单中有一个input标签,input的value值必须是我们设置在constructor构造函数的state中的值,然后,通过onChange触发事件来改变state中保存的value值,这样形成一个循环的回路影响。
于受控组件与非受控组件的特点,二者应用的地方也有所不同,主要表现在:
受控元素,一般用在需要动态设置其初始值的情况;例如某些form表单信息编辑时,input表单元素需要初始显示服务器返回的某个值然后进行编辑。
非受控元素, 一般用于无任何动态初始值信息的情况; 例如form表单创建信息时,input表单元素都没有初始值,需要用户输入的情况
setState
-
不可变值(push,pop,splice直接操作this.state中数组会改变值,而slice,concat操作会返回新的数组)
-
可能是
异步更新(setstate后,立即去拿结果,拿不到最新的值)isBatchingUpdates 机制,true为异步, false为同步 1、 isBatchingUpdates = true this.setState({ count: this.state.count +1 }, () => { isBatchingUpdates = false // 想当于vue中的$nextTick console.log(this.state.count) // 这里就可以获取到最新的值 }) isBatchingUpdates = false 结束 2、setTimeout中setState是同步的 isBatchingUpdates = true setTimeout(function(){ isBatchingUpdates =false this.setState({ count: this.state.count+1 }) console.log(this.state.count) // 这里就可以获取到最新的值,不用回调 }) 3、自己定义的DOM事件,setState是同步的 具体函数名(){ isBatchingUpdates = false this.setState({ count: this.state.count+1 }) console.log(this.state.count) // 这里就可以获取到最新的值,不用回调 } componentDidMount(){ isBatchingUpdates = true document.body.addEventListener('click', this.具体函数名) // 最后要销毁该函数名,容易造成内存谢泄漏 } componentWillUnmount(){ // 及时销毁自定义的dom事件 doucument.body.removeEventLIstener('click',this.具体函数名) } 异步还是同步 setState无所谓异步还是同步 看是否命中batchUpdate机制(看是否为react的入口,如生命周期,自定义函数) 判断isBathingUpdates
-
可能会被合并
传入对象,会被合并,(类似Object.assign) 执行结果只一次+1(因为是异步的,都拿到的数据是相同的,+1不变) this.setState({ count: this.state.count+1 }) this.setState({ count: this.state.count+1 }) this.setState({ count: this.state.count+1 }) 传入函数,不会被合并,执行结果+3 this.setState((preState, props) => { return { count: preState.count + 1 } }) this.setState((preState, props) => { return { count: preState.count + 1 } }) this.setState((preState, props) => { return { count: preState.count + 1 } })
函数组件
- 纯函数,输入props, 输出jsx
- 没有实例,没有生命周期,没有state
- 不能扩展其他方法
Portals
我们创建了一个子组件后,要把它放到指定的dom元素下面,该怎么办?
插槽(Portals)能将子节点渲染到父组件的 DOM 层次之外
使用Portals渲染到body上,
相当于vue中的插槽
场景
对于 portal 的一个典型用例是当父组件有 overflow: hidden 或 z-index 样式,但你需要子组件能够在视觉上 “跳出(break out)” 其容器。例如,对话框以及提示框。
overflow: hidden
父组件z-index值太小
fixed 需要放在body第一层级
ReactDOM.createPortal(child, container)// 组件结构还是那个结构,只是把这个(子组件)渲染到了其他地方
context
- 公共信息(语言、主题)如何传递给每个组件?
- 用props太繁琐
- 用redux小题大做
Contex 的 API 在新 react 版本中变动还是很大的,我们这里通过一个实例为大家讲解一下,如果以前没有接触过 context ,也可以借此机会了解一下 context 的强大之处。首先大家要明白一些概念,首先是 react 组件间传递数据是通过 props 向下(也就是想子组件传递),是单向传递的,从父级一层一层地通过 props 地向下传递到子子孙孙,有的时候我们组件一层一层的嵌套多层,这样这种方式一层一层传递麻烦,我们可不可以进行跃层传递,这就会用到 context。
如果我们不想通过props实现组件树的逐层传递数据,则可以使用context实现跨层级进行数据传递!
React.createContext()
这个方法用来创建context对象,并包含Provider、Consumer两个组件 <Provider />、<Consumer />
只要使用了context都需要调用这个
const {Provider, Consumer} = React.createContext();
Provider
数据的生产者,通过value属性接收存储的公共状态,来传递给子组件或后代组件
eg:
<Provider value={/* some value */}>
Consumer
数据的消费者,通过订阅Provider传入的context的值,来实时更新当前组件的状态
eg:
<Consumer>
{value => /* render something based on the context value */}
</Consumer>
再最外层的组件上,通过生产者Provider组件进行包裹,并存储共享数据到value中,当然可以是任何数据类型。后带需要用到共享数据的组件均可通过Consumer进行数据获取。
异步组件
-
import () vue
-
React.lazy
-
React.Suspense
-
组件大,路由需要进行懒加载时
没有异步加载 import Comp from './' 异步加载 const Comp = React.lazy(() => import('./')) class App extends COmponent{ render() { return { <React.Suspense fallback={<div>Loading...</di>}> <Comp/> </React.Suspense> } } } // 强制刷新,可看到loading(看不到就限制一下chrome的网速)
性能优化
- shouldComponentUpdate(不建议深度比较,耗性能)
- PureComponent和React.memo
- 不可变值immutable.js
react 默认是父组件更新子组件无条件更新
SCU默认返回true,即react默认重新渲染所有子组件
必须配合“不可变值”一起使用
可先不用SCU,有性能问题时再考虑使用
PureComponent,实现了浅比较SCU, 都要有不可变值
immutable
彻底拥抱不可变值
基于共享数据(不是深拷贝,速度好)
有一定的学习成本,按需使用
关于组件公共逻辑的抽离
- mixin 已被React弃用
- 高阶组件HOC
- Render Props
高阶组件
function ppHOC(WrappedComponent) {
return class PP extends React.Component {
constructor(props){
super(props)
this.state={
mouse: {}
}
}
render() {
return <WrappedComponent {...this.props} mouse={this.state.mouse}/>
}
}
}
React 原理
-
函数编程
-
vdom和diff
-
jsx的本质
-
合成事件
-
setState batchUpdate
-
组件渲染过程
函数式编程
- 一种编程范式,概念比较多
- 纯函数
- 不可变值
jsx本质
React.createElement即h函数,返回vnode
第一个参数, 可能是组件,也看是HTML tag
组件名,首字母必须大写(react规定)
合成事件
所有事件挂载到document上
event不是原生的,是syntheticEvent合成事件对象
和Vue事件不同,和dom事件也不同
回顾
event是SyntheticEvent模拟出来的,模拟出来dom事件所有能力
event.nativeEvent是原生事件对象
所有的事件,都被挂载到document
和DOM事件不一样,和vue事件也不一样
为什么要合成事件
更好的兼容性和跨平台
载到document,减少内存消耗,避免频繁解绑
方便事件的统一管理
如果DOM上绑定了过多的事件处理函数,整个页面响应以及内存占用可能都会受到影响。React为了避免这类DOM事件滥用,同时屏蔽底层不同浏览器之间的事件系统差异,实现了一个中间层——SyntheticEvent。
当用户在为onClick添加函数时,React并没有将Click时间绑定在DOM上面。
而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装交给中间层SyntheticEvent(负责所有事件合成)
所以当事件触发的时候,对使用统一的分发函数dispatchEvent将指定函数执行。
组件渲染过程
组件渲染更新
- 渲染过程
- props state
- render() 生成vnode
- patch(elem, vnode)
- 更新过程
- setState(newState) --> dirtyComponents(可能有子组件)(当前组件的state属性被改,子组件的值也有可能被改)
- render()(jsx结构)生产newVnode
- patch(vnode,newVode)
更新的两个阶段
- 上述的patch被拆分为两个阶段:
- reconciliation阶段-执行diff算法,纯js计算
- commit阶段 - 将diff结果渲染DOM
可能会有性能问题
- js是单线程,且和dom渲染共用一个线程
- 当组件足够复杂,组件更新时计算和渲染都压力大
- 同时再有dom操作需求(动画、鼠标拖拽)将卡顿
解决方案fiber
- reconciliation阶段进行任务拆分(commit无法拆分)
- dom需要渲染时暂停,空闲时恢复
- window.requestIdleCallback
函数组件和class组件区别
- 纯函数,输入props,输出jsx
- 没有实例,没有生命周期,没有state
- 不能扩展其他方法
什么是受控组件
- 表单的值,受state控制
- 需要自行监听onChange,更新state
- 对比非受控组件
何时使用异步组件
- 同vue
- 加载大组件
- 路由懒加载
多个组件有公共逻辑,如何抽离
- 高阶组件HOC
- Render props
redux 如何异步请求
- 异步action
- 如redux-thunk
React 事件和Dom事件的区别
- 所有事件挂载到document上
- event不是原生的,是SyntheticEvent合成事件对象
- dispatchEvent机制
性能优化
- 渲染列表时加key
- 自定义事件、dom事件及时销毁
- 合理使用异步组件
- 减少函数bind this 的次数
- 合理使用Immutable.js
- webpack层面的优化
- 前端通用的性能优化,如图片懒加载
- 使用SSR
- 合理使用SCU PureComponent 和memo
React.memo
React.memo() 和 PureComponent 很相似,它帮助我们控制何时重新渲染组件。
组件仅在它的 props 发生改变的时候进行重新渲染。通常来说,在组件树中 React 组件,只要有变化就会走一遍渲染流程。但是通过 PureComponent 和 React.memo(),我们可以仅仅让某些组件进行渲染。
PureComponent 要依靠 class 才能使用。而 React.memo() 可以和 functional component 一起使用。
import React from 'react';
const MySnowyComponent = React.memo(function MyComponent(props) {
// only renders if props have changed!
});
// can also be an es6 arrow function
const OtherSnowy = React.memo(props => {
return <div>my memoized component</div>;
});
// and even shorter with implicit return
const ImplicitSnowy = React.memo(props => (
<div>implicit memoized component</div>
));
React 和Vue 的区别
相同
- 都支持组件化
- 都是数据驱动视图
- 都使用vdom操作dom
区别
-
React 使用jsx拥抱js,vue使用模板拥抱html
-
React函数式编程,Vue声明书编程
-
react更多需要自力更生,Vue把想要的都给你