React学习笔记

一、react基本概念

  1. 官方脚手架构建react应用
npm install cnpm -g
cnpm install create-react-app -g
create-react-app my-app
cd my-app
cnpm install 
  1. 如何构建一个组件页面
    (通过函数 或 class)
import React from 'react'
class XXX extends React.Component{
   render(){
     return <div>页面</div>
   }
}
export default XXX;
  1. 状态管理state props
    (状态变化会触发render,重新渲染页面)
constructor(props){
   super(props)
   this.state = {
      name: this.props.name
   }
}
  1. 组件间值传递
  • 父组件 -> 子组件: 通过给子组件的设置属性
    父:
    子: this.props.name
  • 子组件 -> 父组件: 通过给子组件设置回调函数
    父:
    onChildOk = data => {
    //接受子组件的值 }
    子:this.props.onOk(data)
  1. 组件的生命周期
  • construtor 初始化,构造函数
    this.state = {} – 初始化state
    super(props) – 在构造函数内部初始化this.props
  • UNSAFE_ componentWillMount 组件挂载前
    给state赋值,请求数据、生成资源
  • render 挂载 or 更新页面
    初始化 或者 state、props发生变化时
    渲染页面 (通过diff计算虚拟dom,生成/更新真实的dom)
  • componentDidMount 组件挂载后
    请求数据、生成资源
  • UNSAFE_ componentWillReceiveProps 仅在props发生变化时(组件初始化或state变化不触发)
    UNSAFE_ componentWillReceiveProps(nextProps){
    this.props.name xuyuan
    nextProps xuzhif
    }
  • shouldComponentUpdate 组件是否应该被更新
    (nextProps,nextState)
    返回true更新 返回false不更新
  • UNSAFE_ componentWillUpdate 组件更新前
    (nextProps,nextState)
    尽量不要在这个阶段更新state,容易引起死循环
  • componentDidUpdate 组件更新后
    (prevProps,prevState)
  • componentWillUnmount 组件卸载前
    释放资源
    在这里插入图片描述
  1. react和传统前端开发的区别
    (组件、状态和 JSX)
    在这里插入图片描述
    React 组件的模型是从 Model 到 View 的映射,这里的 Model 对应到 React 中就是 state 和 props。在过去,我们需要处理当 Model 变化时,DOM 节点应该如何变化的细节问题。而现在,我们只需要通过 JSX,根据 Model 的数据用声明的方式去描述 UI 的最终展现就可以了,因为 React 会帮助你处理所有 DOM 变化的细节。而且,当 Model 中的状态发生变化时,UI 会自动变化,即所谓的***数据绑定***。

所以我们可以把 UI 的展现看成一个***函数***的执行过程。其中,Model 是输入参数,函数的执行结果是 DOM 树,也就是 View。而 React 要保证的,就是每当 Model 发生变化时,函数会重新执行,并且生成新的 DOM 树,然后 React 再把新的 DOM 树以最优的方式更新到浏览器。

  • 虚拟DOM
    通过在内存中维护的virtual dom,状态发生变化时,通过diff算法计算出结果后再更新真实的dom
  • JSX语法糖 (js和html写在一起)
  • 单页应用
  • 组件化
    以组件的方式构建UI
    内置组件。内置组件其实就是映射到 HTML 节点的组件,例如 div、input、table 等等,作为一种约定,它们都是小写字母。
    自定义组件。自定义组件其实就是自己创建的组件,使用时必须以大写字母开头,例如 MyButton、Modal
  • 单向数据流、状态管理
    React 的核心机制是能够在数据发生变化的时候自动重新渲染 UI,那么势必要有一个让我们保存状态的地方,这个保存状态的机制就是 state。而 props 就是类似于 Html 标记上属性的概念,是为了在父子组件之间传递状态

在 React 之前,我们需要调用 DOM 的 API 来修改 DOM 树的结构,从而改变 UI 的展现。而在有了 React
之后,我们只需要在业务状态和 UI 状态之间建立一个绑定的关系就行了。绑定完成后,我们就不需要再关心怎么去精细控制 UI 的变化,因为
React 会在数据发生变化时,帮助我们完成 UI 的变化

  1. 相关资源
    https://edu.51cto.com/course/12276.html?edu_recommend_adid=99

二、组件库

1. 用vite构建react应用
         https://vitejs.cn/
          为什么选择vite:新一代的构建工具,快速构建、打包和热重载
cnpm install vite -g
npm init vite@latest my-vite-app --template react
cd my-vite-app
cnpm install
2. 相关组件库
  • less
    css预处理语言,扩展css语法
    学习: https://less.bootcss.com/
    安装: cnpm install less
    cnpm install less-loader

  • moment
    高效的日期处理类库
    学习: http://momentjs.cn/
    安装: cnpm install moment --save

  • Ant Design
    企业级的UI组件库
    学习: https://ant-design.antgroup.com/index-cn
    安装: cnpm install antd --save

3. 学习react-router
          路由的2种模式

○ hash http://www.baidu.cn/#/home
#以后的内容不会包含在http的请求中
○ history http://www.baidu.cn/home
需要后端处理匹配页面跳转

  • react-router
    前端路由
    学习: https://zhuanlan.zhihu.com/p/431389907
    安装: cnpm install react-router-dom
4. 学习全局状态管理(redux、mobx)
  • mobx
    全局状态管理
    学习: https://www.mobxjs.com/
    安装: cnpm install mobx
    cnpm install mobx-react
<Provider store={XXX}> 
</Provider>    
@observable   @action
 
@inject('XXX') @observer

开启装饰器:
cnpm install @babel/plugin-proposal-decorators
cnpm install @babel/plugin-proposal-class-properties

plugins: [
    react({
      babel: {
        plugins: [
          ["@babel/plugin-proposal-decorators", { legacy: true }],
          ["@babel/plugin-proposal-class-properties", { loose: true }],
        ],
      },
    }),
  ],
5. 学习axios
  • axios
    http请求
    学习: http://www.axios-js.com/
    安装: cnpm install axios

封装请求

6. 构建完整的前端框架
  • 框架库 react
  • 前端路由 react-router、react-router-dom
  • 全局状态管理 redux、mobx、vuex、flux
  • UI库 antd、mui、bootstrap
  • 请求库 axios 、fetch
  • 第三方扩展 less、moment、lodash、charts、cookies、react-use等等
7. 封装前端功能,项目分层

项目结构示例

      - my-app    (项目文件夹)
            - dist     (打包目录)
            - node_modules     (nodejs模块目录)                    - src        (项目主体内容)
                 - assets   (静态资源、图片)
                 - model      (全局状态管理)
                 - service   (接口请求管理)
                 - utils         (工具类)
                 - components  (自定义组件)
                 - router       (路由配置)
                 - config       (配置文件、环境变量)
                 - views        (页面组件)
                       -- login
                       -- home
                       -- query
                       -- system
            - index.html     (入口html)
            - package.json    (项目描述文件,项目基本信息、第三方依赖)
            - vite.config.js      (开发配置)

三、高阶组件 HOC

高阶组件能够让我们写出更易于维护的react代码 ,优雅地拆分组件​和功能 (装饰者模式、 面向切面)
以组件为参数,返回值为新组件的函数。
用于组件重用和逻辑封装(如 修改、添加props、日志打点、权限控制、表单校验)

组件和 高阶组件的区别

  • 组件是将 props 转换为 UI
  • 高阶组件是将组件转换为另一个组件
function withUserData(WrappedComponent) {
       return class extends React.Component {
           constructor(props) {
               super(props)
               this.state = { userInfo: {} }

           }
           componentDidMount() {
               let userInfo = JSON.parse(localStorage.getItem("userInfo"))
               this.setState({ userInfo })
           }
           render() {
               // ...this.props 传递给当前组件的属性继续向下传递
               return <WrappedComponent userInfo={this.state.userInfo} {...this.props} />
         }
      }
  }

如何理解这段代码
inject(“store”)(observer(Home))

在这里插入图片描述

四、react hooks

本质是函数组件 + 状态 + 生命周期管理
代码更加简洁,业务逻辑复用,分离业务逻辑,让代码更加清晰和易于维护

  • useState
    让函数具有状态管理能力
const [count, setCount] = useState(0)

状态 count
更新count的函数 setCount
0 赋初始值

  • useEffect
    执行副作用,副作用是指一段和当前执行结果无关的代码。比如说要修改函数外部的某个变量,要发起一个请求,等等。也就是说,在函数组件的当次执行过程中,useEffect 中代码的执行是不影响渲染出来的 UI 的。
 useEffect(callback, dependencies)

要执行的函数 callback
可选的依赖项数组 dependencies

useEffect 涵盖了 ComponentDidMount、componentDidUpdate 和 componentWillUnmount 三个生命周期方法

返回一个函数,用于在组件销毁的时候做一些清理的操作 (componentWillUnmount)

  • 用法一 (没有传dependencies)
    每次render后都会执行(ComponentDidMount、componentDidUpdate)
useEffect(() => {
   console.log("执行代码")
   return () => {
       console.log("componentWillUnmount")
   }
})
  • 用法二 (dependencies传空数组)
    只在首次执行的时候触发 (ComponentDidMount)
useEffect(() => {
   console.log("执行代码")
   return () => {
       console.log("componentWillUnmount")
   }
},[])
  • 用法三 (dependencies传含参数的数组)
    传入的参数变化才会执行
useEffect(() => {
   console.log("执行代码")
   return () => {
       console.log("componentWillUnmount")
   }
},[count,num])

总结一下,useEffect 让我们能够在下面四种时机去执行一个回调函数产生副作用:
1、每次 render 后执行:不提供第二个依赖项参数。比如useEffect(() => {})。
2、仅第一次 render 后执行:提供一个空数组作为依赖项。比如useEffect(() => {}, [])。
3、第一次以及依赖项发生变化后执行:提供依赖项数组。比如useEffect(() => {}, [deps])。
4、组件 unmount 后执行:返回一个回调函数。比如useEffect() => { return () => {} }, [])。
— 优化Hooks

  • useCallback
    缓存回调函数,避免重复计算
//使用前
function Counter() { 
  const [count, setCount] = useState(0); 
  const handleIncrement = () => setCount(count + 1); 
  return <button onClick={handleIncrement}>+</button>
}
//使用后
function Counter() { 
  const [count, setCount] = useState(0); 
  const handleIncrement = useCallback(
            () => setCount(count + 1),
            [count], // 只有当 count 发生变化时,才会重新创建回调函数
  ); 
  return <button onClick={handleIncrement}>+</button>
}
  • useMemo
    缓存计算结果,避免重复计算
export default function App() {
  const [count, setCount] = useState(0);
  const [total, setTotal] = useState(0);

  // 没有使用 useMemo,即使是更新 total, countToString 也会重新计算
  const countToString = (() => {
    console.log("countToString 被调用");
    return count.toString();
  })();

  // 使用了 useMemo, 只有 total 改变,才会重新计算
  const totalToStringByMemo = useMemo(() => {
    console.log("totalToStringByMemo 被调用");
    return total + "";
  }, [total]);

  return (
    <div className="App">{countToString}</div>
    )
}
  • useRef
    多次渲染之间共享数据 ,一般用useRef保存的数据,和UI的渲染无关,当ref更新时,不会触发组件的重新渲染
    保存某个dom节点的引用
    ( 能否用 state 去保存 timer.current )
import React, { useState, useCallback, useRef } from "react";
export default function Timer() { 
  // 定义 time state 用于保存计时的累积时间 
  const [time, setTime] = useState(0); 
  // 定义 timer 这样一个容器用于在跨组件渲染之间保存一个变量 
  const timer = useRef(null); 
  // 开始计时的事件处理函数 
  const handleStart = useCallback(() => { 
    // 使用 current 属性设置 ref 的值 
    timer.current = window.setInterval(() => { 
      setTime((time) => time + 1);
    }, 100);
   }, []); 
  // 暂停计时的事件处理函数 
  const handlePause = useCallback(() => { 
    // 使用 clearInterval 来停止计时     window.clearInterval(timer.current); 
    timer.current = null; 
  }, []); 
return <div>      
       {time / 10} seconds.      
       <br />      
       <button onClick={handleStart}>Start</button>      
       <button onClick={handlePause}>Pause</button>    
     </div>
}
function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // current 属性指向了真实的 input 这个 DOM 节点,从而可以调用 focus 方法
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}
  • useContext
    定义全局状态,在多个函数组件中共享状态
    redux正是利用context的机制来提供更可靠的状态管理
const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};
// 创建一个 Theme 的 Context

const ThemeContext = React.createContext(themes.light);
function App() {
  // 整个应用使用 ThemeContext.Provider 作为根组件
  return (
    // 使用 themes.dark 作为当前 Context 
    <ThemeContext.Provider value={themes.dark}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

// 在 Toolbar 组件中使用一个会使用 Theme 的 Button
function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

// 在 Theme Button 中使用 useContext 来获取当前的主题
function ThemedButton() {
  const theme = useContext(ThemeContext);
  return (
    <button style={{
      background: theme.background,
      color: theme.foreground
    }}>
      I am styled by theme context!
    </button>
  );
}
  • useReducer
    useState 的替代方案,适用于更复杂的场景
import React,{useReducer} from 'react'

export default function ReducerDemo() {
    const [count, dispath] = useReducer((state,action)=> {
        if(action === 'add'){
            return state + 1;
        }
        return state;
    }, 0);
    return (
        <div>
            <h1 className="title">{count}</h1>
            <button className="btn is-primary"
                onClick={()=> dispath('add')}
                >Increment</button>
        </div>
    )
}

如何在hooks中使用mobx?

import React from "react";
import { inject, observer } from 'mobx-react';

function TestHook({ store }){
    return <div>{store.User.state.tel}</div>
}

export default inject("store")(observer(TestHook));

五、React-Router v6

  1. 多级路由配置
//父级路由 path配置 * 表示模糊匹配
function App() {
  return <BrowserRouter>
      <Routes>
        <Route path="/login" element={<Login />} />
        <Route path="/home/*" element={<Home />} />
        <Route path="*" element={<Login />} />
      </Routes>
    </BrowserRouter>
}
export default App;

//子路由
function Home(){
  return <Routes>
     <Route path="page" element={<HomePage />} />
     <Route path="art" element={<Art />} />
     <Route path="upload" element={<UploadArt />} />
     <Route path="*" element={<HomePage />} />
   </Routes>
}
export default Home;

  1. 与v5的变化
  • Routes 替代 Switch
  • Route的element 替代 component
  • Route废弃exact属性
  • useRoutes代替react-router-config
import { useRoutes } from 'react-router-dom'
function App() {
  return useRoutes([
     { path:'/login',element: <Login /> },
     { path:'/home/*',element: <Home /> },
     { path:'*',element: <Login /> },
  ])
}
export default App;
  • useNavigate代替useHistory
//尽量改为用Hooks写页面
import { useNavigate } from 'react-router-dom';
const navigate = useNavigate()
navigate('/home')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值