React 基础 2

生命周期

1 挂载阶段
  1 constructor()  -->  组件的创建到销毁, 只执行一次
	1 它是class组件类的构造器, 当组件实例化时首先被调用
	2 是所有生命周期中, 第一个执行的
	3 内部用于定义, class类组件的变量, 且不可以使用this.setState()方法

  2 render()  ---> 组件的创建到销毁, 可执行多次
	1 是所有生命周期中, 唯一的必须存在的生命周期
	2 用于定义 class类组件视图的, 必须有 return 返回值, 且返回 JSX 元素对象
	3 return 之前用于做业务逻辑, 该函数中不可使用 this.setState()方法
	4 在装载阶段和更新阶段都会执行
	5 书写的时候, 往往放在当前组件的最后面
		
  3 componentDidMount()  --> 组件的创建到销毁, 只执行一次 --> 常用
	1 相当于 Vue中的 mounted()  表示视图初始化渲染完成
	2 我们经常在此处 -- 触发调接口, 开启定时器, 长链接, DOM操作

2 更新阶段
  1 componentDidUpdate()  --> 不常用
	1 相当于是 Vue中的 updated(), 它表示视图更新已完成
	2 此处也不能使用 this.setState()
	3 主要作用就是, 性能优化, 抽离处不参与视图渲染的变量, 让他们不执行diff运算

  2 shouldComponentUpdate()  --> 不常用
	1 它是一个开关, 用于控制组件的更新
	3 这个生命周期一定要返回一个布尔值, 返回 false, 更新失败

3 卸载阶段
  1 componentWillUnmount()  --> 常用
	1 相当于是 Vue中的 beforeDestroy()
	2 在这里一般做清除定时器, 长连接, 清除状态管理的缓存

组合

1 组合在react中,是一种非常强大的组件复用的设计模式
2 本质上解决的是组件之间传值的问题, 它对于传值以及一些内部操控的逻辑封装得更严密
3 这种模式比较好的把复杂逻辑完全封装起来了, 比较适合开发组件的开发者
4 针对props的扩展性也比较好,对于使用组件的开发者来说,也比较友好

上下文

1 作用
  1 Context 通过组件树提供了一个传递数据的方法, React.createContext()创建上下文
  2 可以在 React组件树中进行数据传递, 避免使用复杂的链式的 props 
  3 上下文数据只能单向传递,从父组件向内部组件传递,不能倒着来

高阶组件

1 概念
--------------------------------------------------------------------------
  1 高阶组件 == 高阶函数 == 容器组件 / 被其修饰的组件 == UI组件
  
  2 作用说明
    1 业务逻辑复用的高级技巧, 可让某一个组件, 通过高阶函数内部修饰, 实现功能扩展
    2 高阶组件是非必须使用的, 宏观作用就是, 减少代码量, 让代码变得优雅简洁, 方便管理
    
  3 理解
    1 是基于React组件的组合特性而来一种设计模式
    2 高阶组件就是一个函数, 接收组件, 基于这个类做一些扩展, return 一个新的组件出去
    3 这个新的组件就包含了, 高阶函数内部的方法以及数据, 以及接收进来的组件实例
    4 并且高阶函数内的新组件会向, 接收进来的组件实例, 以父子通信的方式传递需要的数据
    5 也可以把高阶组件理解为一个工厂, 统一加工一些, 需要扩展某些相同功能的组件类

  4 使用场景
    1 若有 9个组件需要同一个接口数据, 可以把数据请求放在高阶函数内, 去帮需要的组件扩展
    2 某些视图结构 (HTML结构), 需要被多个组件视图复用的情况
    3 某些业务逻辑, 功能方法等, 需要在多个组件中复用的情况

  3 注意
    1 当一个UI组件同时被多个容器组件(高阶函数)修饰时, 发现 props有丢失的情况, 处理方案
      1 以后写代码, 若需要被多个高阶组件修饰, 习惯性加这个展开运算符
      2 高阶函数中, UI组件实例的位置: <A1 {
    
    ...this.props} />
    2 class 类组件的装饰器语法, 知道就行了, 花里胡哨的不好用 --> @xx calss ...
----------------------------------------------------------------------------

4 高阶组件的 定义 + 使用
----------------------------------------------------------------------------
1 定义高阶函数 Test()
import React from 'react'
function Test(A1) {
    
      // A1 就是UI组件, 就是被修饰的组件类
  return class extends React.Component {
    
    
    constructor(props) {
    
    
      super(props)
      this.state = {
    
    
		list: []
      } 
    } 
    componentDidMount() {
    
    
      // 模拟调接口, 获取到如下数据
      const arr = [
        {
    
    id: 1, label: 'hehe1'},
        {
    
    id: 2, label: 'hehe2'},
        {
    
    id: 3, label: 'hehe3'}
      ]
      this.setState({
    
    list: arr})
    }
    // 类似父子组件传值
	render() {
    
     return() {
    
     <div> <A1 {
    
    ...this.props} hh="hehe" arrs={
    
    list}/> </div>}}
  }
}
export default Test

2 UI组件使用高阶函数 Test()的过程
  import React from 'react'
  import Test from '@/hoc/Test'
  const A1 = props=> {
    
    console.log(this.props)}  // {hh: "hehe", arrs: Array(3)}
  export default Test(A1) 
----------------------------------------------------------------------------

HOOK

1 概念
  1 从React 16.8 开始,增加 Hook 新特性
  2 作用: 使用函数式组件, 也可以使用到生命周期, state 等特性
  3 好处: 高性能的同时, 使用生命周期等特性
  4 理解: HOOK 实际上就是一组 api,帮助你在函数式组件中, 使用React的固有特性

2 定义函数式组件的方式
  1 function A1(props) {
    
     return (<div> 呵呵</div>)}
  2 const A2 = props => {
    
     return (<div> 呵呵</div>)}
  3 const A2 = props => (<div> 呵呵</div>)
----------------------------------------------------------------------------

3 函数式组件中使用 state --> useState()
----------------------------------------------------------------------------
  1 按需引入
  	import React from 'react'
	import {
    
    useState} from 'react'

  2 函数式组件中定义变量
  	export default props => {
    
    
  	  1 使用API useState() , 定义一个声明式变量 msg1, 初始值为 1  //一定要有初始值
  	  2 同时定义一个 setMsg1方法, 专门用于修改声明式变量 msg1, 并且会触发 diff运算
  	  const [msg1, setMsg1] = useState(1)  // 初始化为 1的数字
  	  const [msg2, setMsg2] = useState([])  // 定义一个空数组
  	  const [msg3, setMsg3] = useState(true)  // 定义一个布尔值

	  3 定义组件方法 -- 注意不能修改变量本身的值, 可以是一个表达式结果 (setMsg1会修改)
  	  function add() {
    
    setMsg1(msg1+1)}      // 定义方式 1
  	  const sub = () => {
    
    setMsg1(msg1-1)}   // 定义方式 2
  	  
  	  4 组件视图
	  return (
		<div>
      	  <h3> {
    
    msg1} </h3>
      	  <button onClick={
    
    add}> +1 </button>  // 调用组件方法 add
      	  <button onClick={
    
    sub}> -1 </button>  // 调用组件方法 sub
      	  <button onClick={
    
    ()=>setMsg1(msg1+1)}> +1 </button>  // 简单操作方式
   	    </div>)
	}
----------------------------------------------------------------------------

4 函数式组件中使用副作用 -->  useEffect() 
----------------------------------------------------------------------------
1 概念
  1 副作用: 调接口, 定时器, DOM操作, 长连接等 逻辑都叫做副作用 (会影响组件性能)
  2 通常这样的副作用, 写在生命周期函数里, 但是函数式组件中没有, this和生命周期函数
  3 那么 useEffect API 就可以帮我们模拟出生命周期的特性, 然后就可以在函数式组件中执行副作用了

2 理解
  1 在一个组件中可以使用多个副作用, (且当前副作用不会影响其他副作用)
  2 通常一个副作用只做一件事, (避免代码相互干扰)
  3 基础语法
	1 ES6: useEffect(()=>{
    
    return ()=>{
    
    }}, [])
	2 ES5: useEffect(function() {
    
    return function() {
    
    }}, [])

3 操作流程
  1 按需引入
  import React from 'react'
  import {
    
    useState} from 'react'

  2 使用 useEffect
  export default props => {
    
     
	const [msg1, setMsg1] = useState(1)
		useEffect(()=> {
    
    
	  // do something (调接口等)
	  return ()=> {
    
    
		// do something (关定时器等)
	  }
	}, [])  // 默认写 [], 若要在某个变量改变的时候, 重新触发 useEffect, 这么写 [msg]

	useEffect(()=>{
    
    return ()=>{
    
    }}, [msg1])  // msg1每次改变, 就会再运行一次模拟生命周期
	useEffect(()=>{
    
    return undefined}, [])  // 什么都不做也要返回一个 undefined
	return () 
  }

React 路由

1 概念
----------------------------------------------------------------------------
  1 React 路由特点都是组件化的
  2 react-router 是基于上下文实现的
  3 路由配置的流程
    1 路由模式的选择
    2 修改 url的操作接口 (可以后写)
    3 配置路由映射关系 (就是路由和对应组件的匹配规则)
  4 
  5 
----------------------------------------------------------------------------
  
2 安装
----------------------------------------------------------------------------
  1 React路由有3个库 -- react-router / react-router-dom / react-router-native
  2 npm install react-router -S
  3 npm install react-router-dom -S  ( 建议安装这个, 其实安装上面的也可以)
----------------------------------------------------------------------------
  
3 路由模式的选择 (俩种)
----------------------------------------------------------------------------
  1 let {
    
     HashRouter, BrowserRouter} from 'react-router-dom'
  2 哈希模式: <HashRouter> <div>呵呵</div> </HashRouter>  
  3 history 模式: <BrowserRouter> <div>呵呵</div> </BrowserRouter> 
  4 用引入的组件实例 HashRouter把, 把组件视图包起来, 该组件就有了路由的功能
----------------------------------------------------------------------------

4 改变url的方式 (俩种) + 基础路由匹配规则
----------------------------------------------------------------------------
1 声明式路由跳转 -- App.js
  1 let {
    
     HashRouter, NavLink, Link, Route, Redirect} from 'react-router-dom' 
  2 <HashRouter> 视图结构 </HashRouter>  // 1 选择路由模式
  3 视图结构中(定义 3个改变 url的标签)  // 1 改变 url的操作接口
    1 <NavLink to='/jsx'> jsx学习 </NavLink>  
    2 <NavLink to='/props'> props学习 </NavLink>
    3 <Link to='/hh'> hh</Link>  // NavLink自带高亮样式的, Link没有
  4 视图结构中(定义视图标签 Route)
	1 import Jsx from '@/pages/Jsx'
	2 import Props from '@/pages/Props'
	3 <Route path='/jsx' component={
    
    Jsx}/>  // 对应上面的 url路径
	4 <Route path='/props' component={
    
    Props}/>  // 对应路径显示对应的视图容器
	5 类似 Vue中的视图标签, 但是这么写没有路由配置文件, 代码乱而多, 而且不方便管理
	6 所以我们通常把, 相关数据定义在一个文件中, 然后通过遍历渲染的方式, 在 App.js中定义视图标签

2 编程式路由跳转
  1 凡是被 <Route>元素直接包裹的组件, 它的 props都能拿到路由相关 API 
  2 由于一部分公共组件, 没有在 App.vue中被<Route>渲染和包裹, 所以没有路由相关 API
    1 通过一个内置的高阶组件来扩展
      1 import {
    
     withRouter} from 'react-router-dom'
      2 A1组件: export default withRouter(A1) //该组件props就可以使用路由相关API了
    2 通过内置 API来实现 (推介) 
      // 常用 API: useHistory / useLocation / useParams / useRouteMatch
      1 import {
    
     useHistory} from 'react-router-dom'
      2 const A1 = ()=>{
    
    const h = useHistory()	//即可通过 hh来访问路由相关的 API 了}
  3 公共组件只用路由相关 API, 应该是二级路由的使用需求 
----------------------------------------------------------------------------

5 标准的路由规则映射定义
----------------------------------------------------------------------------
1 创建路由配置文件 src/router/index.js (定义路由映射关系)

2 引入要配置路由的组件
  1 import Jsx from '@/pages/Jsx'
  2 import Props from '@/pages/Props'

3 设置路由配置文件
  export default [
	{
    
    id: 1, path: '/jsx', text: '学习Jsx', component: Jsx},
	{
    
    id: 2, path: '/props', text: '学习Props', component: Props}]

4 App.js 中使用
  1 import routes from '@/router/index.js'
  
  2 定义渲染 NavLink的方法() 
    1 感觉导航栏自己按需添加比较科学, 没必要在此处渲染
    2 类似 Vue中的 router-link, 通过改变 url, 来达到显示路由对应组件的效果
    renderNavLinks() {
    
    return(
      routes.map(v =>(<NavLink key={
    
    v.id} to={
    
    v.path}>{
    
    v.text}</NavLink>)) )}
      
  3 定义渲染视图容器的方法
    1 给所有配置了路由的组件视图, 定义一个对应的视图容器 <Route>
    2 如果自己直接写也是可以的, ( 1级路由文件少的情况下)
    3 因为没有 Vue中的默认视图, 所以配置路由的 1级组件都要, 有自己对应的视图容器才可以显示
	renderRoutes() {
    
    return(
	  routes.map(v=>(<Route key={
    
    v.id} path={
    
    v.path} component={
    
    v.component}/>)}
	  
  4 使用路由
	return (<div>
	  <nav>{
    
    this.renderNavLinks()}</nav>  //渲染我们所配路由的声明式导航, (感觉自己写科学)
	  <div class="main">  
	    {
    
    this.renderRoutes()}
	  </div>
	</div>)

  5 如何实现重定向 Redirect
	1 import {
    
    Redirect, Switch} from 'react-router-dom'
	2 基于上面的代码
	  <div class="main">  //上面渲染视图容器的地方
	    <Switch>  // 设置重定向需要, 用这个标签把, 视图容器标签包裹起来
	      {
    
    this.renderRoutes()}
	      <Redirect from='/*' to='/jsx' />  //表示所有找不到的, 定向到 '/jsx'
	    </Switch> 
	  </div>
----------------------------------------------------------------------------

6 动态路由传参
----------------------------------------------------------------------------
1 路由映射表配置 -->  path: 'jsx/:id'  // 目标页面路由配置
2 路由传参 --> <span onClick={
    
    ()=>props.history.push('jsx'+id)}></span>  // 起始页面
3 目标页面接收路由参数
  1 props.match.params.id   // 直接接收
  2 import {
    
     useParams} from 'react-router-dom'  // 内置 API 接收
    const id = useParams().id 
----------------------------------------------------------------------------

7 代码分割 (路由懒加载)
----------------------------------------------------------------------------
1 理解
  1 把所有的 js文件打包在一个 js文件中, 如果这个项目很大这么干是不可取的, 就要对代码进行分割
  2 Vue 中叫做路由懒加载, 这里叫做代码分割, 也是按需加载

2 步骤
  1 安装
    1 npm i @babel/plugin-syntax-dynamic-import -D   // 用于支持动态导入语法
    2 npm i @babel/preset-react -D   // 
    3 npm i @loadable/component -S   // 用于动态导入组件
  2 使用
    1 import loadable from '@loadable/component'
    2 const Jsx = loadable(()=>import('@/pages/Jsx'))  // 懒加载的写法
    3 const routes = [{
    
    id: 1, path: '/jsx', text: 'jsx语法', component: 'Jsx'}]
    4 export default routes
    5 简写: export default []
----------------------------------------------------------------------------

Axios 调接口

1 安装: npm i axios -S
2 axios 的二次封装, 跟 Vue中是一样的
3 基于二次封装再封装一个 API 接口文件
4 再需要数据的页面, 引入对应接口 API,useEffect() 中请求数据 
5 基本上除了, 调接口的位置, 和数据的处理方式, 跟 Vue是差不太多的 

UI组件库

1 Ant Design
  1 安装: $ npm i antd -S
  2 导入样式 main.js: import 'antd/dist/antd.css'
  3 在单文件组件中: 复制代码使用即可 
  4 主题设置: React Day8 

常用脚手架介绍

1 create-react-app
  1 他是 react官方的一个脚手架, 也是最早出现的一个脚手架
  2 这个脚手架里面的不少功能是需要自己配置的 (前提是把相关配置文件暴露出来)
  3 其他脚手架, 默认配置应该会更全面一点

2 DvaJS
3 umi
4 自己创建

状态管理库 mobx (Vuex)

1 概念
----------------------------------------------------------------------------
  1 作用: 全局组件之间的数据共享, 很方便的做缓存
  2 理解: 由于框架一般都存在, 组件通信, 所以有时候, 全局状态管理也不是必须的
  3 mobx: 是一个状态管理工具, 解决的问题就是组件之间数据共享, 以及缓存问题
  4 安装: npm i mobx -S  // 只是用于定义状态管理容器的
----------------------------------------------------------------------------

2 开始使用
----------------------------------------------------------------------------
1 创建状态管理文件: src/store/index.js
  import X1 from './modules/x1.js'  //状态模块
  class A1 {
    
    constructor( this.x1 = new X1())} //组件实例
  export default new A1()  //实例对象
	
2 创建状态模块: src/store/modules/x1.js(以及定义全局数据)
  import {
    
    
    observable,   // 用于定义可共享的数据,相当于Vuex中的 state
    action,       // 相当于是Vuex中的 mutations + actions
 	computed,     // 相当于是Vuex中的 getters
	makeObservable,
    makeAutoObservable
  } from 'mobx'

  export default class X1 {
    
    
    constructor(
      // makeAutoObservable(this)  // 方式1: 自动把变量改为 observable, 方法改为 action
      makeObservable(this, {
    
    msg1: observable})) // 方式2: 手动改变, 相对灵活
    msg1 = 'hello'
    changMsg() {
    
     this.msg1 = 'xx' 调接口等等} 
    get hh() {
    
    }   // 书写的时候, 计算属性前面要加一个 get
  }
----------------------------------------------------------------------------
3 mobx-react 库
  1 作用: 把状态管理( mobx容器)和 react 联系起来
  2 安装: npm i mobx-react -S 
  
  3 联系起来
    1 import {
    
     Provider} from 'mobx-react'
    2 import store from '@/store/index.js'
    3 <Provider s1={
    
    store}></Provider> 把 App.js的视图结构包裹起来; 且被路由包裹(习惯)
----------------------------------------------------------------------------

4 在组件中使用 mobx 状态数据
----------------------------------------------------------------------------
1 import {
    
     observer, inject} from 'mobx-react'  // 引入俩个高阶组件
2 export default inject(s1)(observer(A1))   // 调用会返回一个新的高阶函数
3 此时 props会多出来 store -- const {
    
     x1} = props.store 
4 直接使用: return (<div> {
    
    x1.msg1} </div>) 
----------------------------------------------------------------------------

5 理解
----------------------------------------------------------------------------
  1 inject(store)(UI组件)   // 表示注入
  2 observer(UI组件)   // 把当前组件变成观察者, 解决全局数据变化不能动态更新数据的问题
  3 在单文件组件中的 useEffect( music.getMusic(参数)) 中触发调接口
----------------------------------------------------------------------------

猜你喜欢

转载自blog.csdn.net/weixin_46178697/article/details/113126454
今日推荐