React基础知识+脑图 —— 干中之干!学习过程中建议准备三瓶水!!

762 阅读10分钟

"一觉醒来又有BUG!"—— 大家好!我是周一觉

还在为React庞大的知识体系而苦恼吗?
还在为学习React不知道从何入手而焦虑吗?
还在为...算了,废话不多说,从这篇React基础知识&脑图开始,我们一起学起来吧!

React基础知识

开始学习之前我会默认您
1.会使用npm安装依赖
2.掌握原生Javascript并有一定的编程基础
3.对React有一定的了解

一、脚手架的选择

(1)create-react-app(官方脚手架,默认webpack打包规则)
(2)Vite+React(尤雨溪团队基于rollup开发的打包工具)
(3)其他......

二、MVC是什么

MVC分别是模型(Model)、视图(View)和控制器(Controller),是一种单向驱动模式。模型表示应用程序中的数据和业务逻辑,视图表示用户界面,控制器则负责处理用户输入并更新模型和视图。MVC 的主要优点是分离关注点,使代码更易于维护和修改。
扩展:MVC和MVVM的区别

三、JSX

1.JSX是什么?

JSX(JavaScript XML)是一种JavaScript的扩展语法,它允许开发者使用类似于XML的语法编写JavaScript代码。在React中,JSX被用作声明式UI的编写方式。

2.JSX渲染机制

第一步:把我们编写的JSX语法,编译为虚拟DOM对象「virtualDOM」
第二步:把构建的virtualDOM渲染为真实DOM
注意:第一次渲染页面是直接从virtualDOM->真实DOM。但是后期视图更新的时候,需要经过一个DOM-DIFF的对比,计算出补丁包PATCH(两次视图差异的部分),把PATCH补丁包进行渲染!!
扩展:React中的DOM-DIFF

四、事件委托

React17以前

委托给document容器,而且只做了冒泡阶段的委托可以通过设置
capture:true属性来启用捕获阶段的委托

React17及以后

委托给#root容器,捕获和冒泡都做了委托对于没有实现事件传播机制的事件
才是单独做的事件绑定例如onMouseEnter/onMouseLeave

五、组件

1.类组件(动态组件)

(1)class语法(有this)

主要知识点
1.super 等于 react.component.call(this,...)
2.默认有个state属性挂载到实例上
3.基于render渲染

(2)生命周期函数

第一次渲染(执行过程)

componentWillMount => render => componentDidMount

组件更新(执行过程)

  1. shouldComponentUpdate
  2. componentWillUpdate
  3. 修改状态值/属性值「让this.state.xxx改为最新的值」
  4. render
  5. componentDidUpdate

若是this.forceUpdate()强制更新,则会跳过should直接从will开始,若是父组件更新触发子组件更新,则子组件内部最开始会多一步componentWillReceiveProps,剩余过程一样

组件卸载(执行过程)

componentWillUnmount

(3)视图更新(修改状态)

this.setState(partialState) 
既可以修改状态,也可以让视图更新

  1. this.setState的第一个参数,可以是一个函数,这个函数的第一个参数是存储之前的状态值prevState,返回的对象是我们想要修改的新状态值,可以实现循环多次只渲染最后一次使用prevState来避免出现不一致或不可预测的状态
  2. this.setState的第二个参数,是一个回调函数callback,在状态更改/视图更新完毕后触发执行,也可以说只要执行了setState,callback一定会执行。

若我们基于shouldComponentUpdate阻止了状态/视图的更新,componentDidUpdate周期函数肯定不会执行了,但是我们设置的这个callback回调函数依然会被触发执行!!
扩展:React中setState是同步还是异步?

this.forceUpdate() 强制更新

当组件的状态或属性更改时,React 会自动重新渲染组件。 但是有时需要强制重新渲染组件,即使它们的状态或属性没有更改,这时可以使用 forceUpdate( )方法。
注意:它会跳过 React 的优化和性能优化

(4)性能优化

PureComponent

PureComponent和Component的区别是
PureComponent会给类组件默认加一个shouldComponentUpdate周期函数
对新老属性做一个浅比较,经过比较后若发生改变则更新,否则不更新

2.函数组件(静态组件)

配合Hooks时为动态组件

(1)直接创建函数(无this)
(2)Hooks函数(大于等于React16.8版本)

useState(在函数组件中使用状态,并且后期基于状态的修改,可以让组件更新)

useState自带了性能优化,修改状态会和之前做比较,类似于PureComponent,参数prev储存上一次的状态值,return返回的信息是我们要修改的状态值

useEffect(在函数组件中,使用生命周期函数)

  1. useEffect没设置依赖
    第一次渲染执行callback//=>componentDidMount
    组件每一次更新完毕执行callback//=>componentDidUpdate
  2. useEffect(callback,[])设置依赖,但是无依赖
    只有第一次渲染完毕后,才会执行callback,
    每一次视图更新完毕后,callback不再执行//=>componentDidMount
  3. useEffect(callback,[xxx,xxx,...])设置依赖,有依赖      
    第一次渲染和任意依赖值改变时,都会执行callback
    组件更新时若依赖无变化,则不会执行callback
    callback的return的返回值(小函数),会在组件释放时执行
    理解为组件发生更新后,执行上一次的return

useLayoutEffect(实现一些需要在 DOM 更新前执行的操作)

他会在 DOM 更新前同步执行,而 useEffect 则是在渲染完成之后异步执行,尽量避免在 useLayoutEffect中修改DOM,可能导致浏览器重绘、闪烁等问题。

useMemo(用于对函数式组件进行性能优化,依赖改变则重新执行)

他的callback是计算函数, 它可以缓存函数的计算结果,并在下一次调用时直接返回缓存结果从而避免重复计算由于 useMemo 的作用是优化性能,因此应该尽量避免在计算函数中进行副作用操作,比如修改组件状态或执行网络请求等操作

useCallBack(用于对函数式组件进行性能优化,依赖改变则重新执行)

他的callback是回调函数,若依赖无变动则不会开辟堆内存,以便提高性能。
父组件嵌套子组件时,父组件要把一个内部的函数, 基于属性传递给子组件时,此时传递的这个方法,用useCallback处理一下会更好。

useImperativeHandle(父组件使用子组件的方法)

第一个参数ref用于引用子组件
第二个参数createHandle是一个回调函数,用于创建一个对象,包含了父组件需要暴露给子组件的方法。 createHandle它指向子组件的实例对象,你可以在这个函数中访问子组件的属性和方法 并返回一个对象,该对象上的方法将被暴露给父组件。

useRef(创建一个ref对象)

下面会具体讲ref相关内容

其他。。。(以上是最常用的Hooks函数)

(3)自定义Hook

自定义hook是一种将状态逻辑封装为可重用函数的方式。
可以帮助开发人员在组件之间共享状态逻辑,从而避免代码重复

要创建自定义hook,只需要编写一个函数,该函数以“use”开头,然后在函数内部编写状态逻辑。通常自定义hook使用React的状态钩子 useState 来管理状态

(4)性能优化
  1. React.memo:在纯函数组件中使用 相当于类组件的PureComponent
  2. useMemo/useCallBack

3.组件调用

  1. 单闭合调用<Component/> 
  2. 双闭合调用<Component> ... </Component>

4.flushsync方法

flushSync() 函数用于同步 React 中的异步更新

在 React 中,当状态或属性发生更改时,React 会异步地重新渲染组件并更新 DOM。
如果需要确保 DOM 中的所有更改都已应用,可以使用 flushSync() 函数来同步这些异步更新

六、Ref

给元素标签设置ref目的是获取对应的DOM元素

1.类组件中使用ref

(1)<h2 ref="titleBox">...</h2>

此方法不推荐使用因为在React.StrictMode模式下会报错
获取:this.refs.titleBox

(2)<h2 ref={x=>this.titleBox=x}>...</h2>

获取:this.titleBox

(3)this.titleBox=React.createRef(); <h2 ref={this.titleBox}>...</h2>

获取:this.titleBox.current

(4)赋值给一个函数子组件会直接报错

解决方案
通过 React.forwardRef 实现ref的转发,配合 useImperativeHandle 来达到获取函数子组件内部的某个元素的目的

扩展:React中的高阶组件

2.函数组件中使用ref

(1)<h2 ref={x=>titleBox=x}>...</h2>

获取:titleBox

(1)const titleBox = React.createRef(); <h2 ref={titleBox}>...</h2>

获取:titleBox.current

(1)const titleBox = useRef(); <h2 ref={titleBox}>...</h2>

获取:titleBox.current

3.小结

React.creatRef:类组件、函数组件
React.useRef:函数组件
在函数组件中使用React.creatRef会浪费性能,因为组件每一次更新都会创造一个全新的 ref 对象,使用React.useRef不会,因为只是函数重新执行。

七、复合组件通信

一、props方案
可以通过将属性传递给子组件来实现通信

  1. 类子组件:在render中,通过this.props解构获取属性
  2. 函数子组件:在函数内部,基于形参props中解构获取属性

二、Context方案
React的creatContext方法可以让组件在不需要逐层传递props的情况下访问全局数据,通过创建一个Context对象,可以将其传递给整个组件树。任何一个组件都可以订阅这个Context从而访问其中的数据。

(1)类组件中使用Context

  1. 创建上下文对象ThemeContext=React.creatContext()
  2. 在祖先组件render的return中渲染的组件用<ThemeContext.Provider>包起来 ThemeContext.Provider中的value={{ 存放传递的数据和状态 }}
  3. 后代使用
    ①先导入上下文对象ThemeContext
    static contextType=ThemeContext之后在render中通过this.context解构来获取之后使用
    ③.在render的return中渲染的组件{context=>{从context中解构来获取,return返回渲染组件 }}<ThemeContext.Consumer>组件包起来使用

(2)函数组件中使用Context

  1. 创建上下文对象ThemeContext=React.creatContext()
  2. 在祖先组件render的return中渲染的组件用<ThemeContext.Provider>包起来 ThemeContext.Provider中的value={{ 存放传递的数据和状态 }}
  3. 后代使用
    ①先导入上下文对象ThemeContext
    ②在return中渲染的组件{context=>{ 从context中解构来获取,return返回渲染组件} }<ThemeContext.Consumer>组件包起来使用
    ③ 从react中解构出useContext这个hook,通过const {xx,xx} = useContext(ThemeContxt)来解构获取,最后在return的渲染元素中直接使用即可

三、ref方案(详情见上面 ref 相关内容)

补充脑图↓↓

基础R.jpg

  • 脚手架的选择
  • MVC是什么
  • JSX是什么
  • React中的事件委托
  • React中的组件
  • React中的ref
  • 复合组件通信方案

这七方面是React中最基础的部分,正所谓万丈高楼平地起,大家一定要吃透这张脑图,后续我会慢慢给本文补充代码来方便大家理解。关于文中扩展部分大家可以自己思考一下,有时间我会单独写一篇关于此部分的文章。

写在最后:本文花费你觉(作者)极大的心思和时间,希望能对大家有所帮助!
PS:这是你觉(作者)第一次发表文章,不足之处还望多多包涵
PS:React全家桶 —— 干中之干系列,我会一点一点来更新,敬请期待
PS:评论区欢迎大家留言讨论
PS:最后点个关注,谢谢各位啦!哈哈哈哈~(周星驰笑)!


作者VX:IBeancurd 有问题可以随时与我联系

下期预告:“干中之干2 —— React路由知识!!”