react入门到精通及高级用法,原理分析

事件

  • 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)
  1. 更新过程
  2. setState(newState) --> dirtyComponents(可能有子组件)(当前组件的state属性被改,子组件的值也有可能被改)
  3. render()(jsx结构)生产newVnode
  4. 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把想要的都给你

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值