react简单入门1

一、3大框架的区别

Vue、React 和 Angular 是目前前端开发中最流行的三个框架,它们各自有着独特的特点和优势。

  • Vue:学习曲线平缓,语法较为简单明了,使用html的模板语法结合指令(如 v-ifv-for 等),快速开发中小型系统。
  • React:学习曲线适中,使用JSX(TSX)语法,将 HTML 嵌入到 JavaScript 代码中,广泛应用于大型和复杂的应用。
  • Angular:学习曲线陡峭,自身内置了一套强大机制,更适合构建企业级的大型应用。
    参考: link.

二、react和vue的共通性

3个框架中共通的部分非常多,Angular使用较少不做说明。下边说明vue和react的部分共通内容。

1. vue的html的模板语法和react的JSX语法有很多相似性。

<!-- vue -->
<div>{{ message }}</div>
<!-- react -->
<div>{ messag }</div>

2. 都使用虚拟DOM来渲染画面。

  1. 虚拟DOM是一个JavaScript对象,它将DOM的状态表示为简单的JavaScript对象,并将这些对象与真实DOM的状态同步。
  2. 虚拟DOM的优点是它可以减少DOM的重新渲染次数,从而提高页面渲染性能。
  3. 当应用的数据发生变化时,Vue/React会先构建一个新的虚拟DOM树,然后Vue会将这个新的虚拟DOM树与之前的树进行对比,找出差异,最后只将需要变化的部分应用到真实的DOM上。
// react
import React from 'react';
import ReactDOM from 'react-dom';
 
// 定义一个简单的函数组件
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}
 
// 渲染组件到 DOM
const rootElement = document.getElementById('root');
ReactDOM.render(<Welcome name="John" />, rootElement);

在这个例子中, 就是一个虚拟 DOM 节点,React 将它渲染成一个包含问候信息的真实 DOM 元素。当 name 属性变化时,React 会比较新旧虚拟 DOM 并只更新真实 DOM 中的文本节点,而不是整个 h1 元素。

3. 都使用生命周期概念。(钩子,hook)

生命周期:一个事物从创建到最后消亡经历的整个过程。

  1. vue2的生命周期:四大阶段,八大方法
    阶段:初始化,挂载,更新,销毁。
    方法:beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed。如下图。
    请添加图片描述
    vue3中生命周期和vue2区别不大,简单参照:

beforeCreate --------> setup(()=>{})
created --------> setup(()=>{})
beforeMount --------> onBeforeMount(()=>{})
mounted --------> onMounted(()=>{})
beforeUpdate --------> onBeforeUpdate(()=>{})
updated --------> onUpdated(()=>{})
beforeDestroy --------> onBeforeUnmount(()=>{})
destroyed --------> onUnmounted(()=>{})
activated --------> onActivated(()=>{})
deactivated --------> onDeactivated(()=>{})
errorCaptured --------> onErrorCaptured(()=>{})

参考: link.

  1. react的类组件的生命周期:只有类组件才有生命周期
    阶段:挂载,更新,卸载

请添加图片描述

生命周期函数触发时机作用函数组件对应hook
constructor创建组件时,最先执行1. 初始化state 2. 创建 Ref等useState
render每次组件渲染都会触发渲染UI函数本身
componentDidMount组件挂载(完成DOM渲染)后1. 发送网络请求 2.DOM操作useEffect
componentDidUpdate组件更新(完成DOM渲染)后可以获取到更新后的DOM内容useEffect
componentWillUnmount组件卸载(从页面中消失)执行清理工作(比如:清理定时器等)useEffect里面返回的函数

参考: link.

三、react的类组件和函数组件的区别:

在React开发中,组件是构建应用程序的基本单元。

类组件:

类组件是React早期版本中使用的组件类型,类组件通常用于具有复杂状态和生命周期方法的组件。
类组件的优点是可以继承和复用,并且可以访问this关键字。

以下是一个简单的 React 类组件代码案例:

import React, { Component } from 'react';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      message: 'Hello, World!',
    };
  }

  componentDidMount() {
    // 组件挂载后执行
  }
 
  componentDidUpdate() {
    // 组件更新后执行
  }
 
  componentWillUnmount() {
    // 组件卸载前执行

  handleClick = () => {
    this.setState({ message: 'Hello, React!' });
  }

  render() {
    return (
      <div>
        <h1>{this.state.message}</h1>
        <button onClick={this.handleClick}>Click me</button>
      </div>
    );
  }
}

export default App;

函数组件:

在 React 16.8 之前,函数组件被称为无状态组件,主要用于展示,不能使用状态(state)和生命周期方法。函数组件的主要优点是简洁易懂。它接收 props 作为输入,返回需要渲染的 JSX。但是在React 16.8 引入了 Hooks 特性,使得函数组件也可以有状态和生命周期,类组件几乎不再使用。

好处:
  1. 更简洁的代码:告别冗长的 Class 语法和繁琐的 this 绑定。
  2. 更好的逻辑复用:自定义 Hook 让我们能够在不同组件之间复用状态逻辑。
  3. 更易理解的组件:将相关的逻辑放在一起,而不是分散在不同的生命周期方法中。

下边是一个简单的函数组件代码:

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Hook简述:

官网概述:以 use 开头的函数被称为 Hook。Hook 比普通函数更为严格。你只能在你的组件(或其他 Hook)的 顶层 调用 Hook。如果你想在一个条件或循环中使用 useState,请提取一个新的组件并在组件内部使用它。

常用Hook:

1. useState:状态钩子。

用于为函数组件引入state状态, 并进行状态数据的读写操作

const [xxx, setXxx] = useState(initValue) 
名词变量函数区分用法
xxx变量状态变量
setXxx函数更新变量xxx的方法
initValue常量初始值
  • 未使用useState例子:
    局部变量无法在多次渲染中持久保存。 当 React 组件时,它会从头开始渲染——不会考虑之前对局部变量的任何更改。
    更改局部变量不会触发渲染。 React 没有意识到它需要使用新数据再次渲染组件。
  let index = 0;

  function handleClick() {
    index = index + 1;
  }
  return(
      <h3>  
        ({index + 1})
      </h3>
)
  • 使用useState实现计数器:
import React,{ useState } from "react";

const NewCount = ()=> {
    const [ count,setCount ] = useState(0)
    addCount = ()=> {
        let newCount = count;
        setCount(newCount +=1)
    }
   return (
       <>
           <p> { count }</p>
           <button onClick={ addCount }>Count++</button>
       </>
   )
}
export default NewCount;

2. useContext:共享状态钩子。

作用就是可以做状态的分发,避免了react逐层通过Props传递数据。也可以说是一种组件间通信方式, 常用于【祖组件】与【后代组件】间通信。

1.创建Context容器对象:

const XxxContext = React.createContext()  

2.渲染子组件时,外面包裹xxxContext.Provider, 通过value属性给后代组件传递数据:

<xxxContext.Provider value={数据}>
	<子组件/>
</xxxContext.Provider>

3.后代组件读取数据:

const {} = useContext(XxxContext)

例如:A组件和B组件需要共享一个状态:

import React, { useContext } from "react";
const HookTest = ()=> {
    const AppContext = React.createContext();
    const A = ()=> {
        const { name } = useContext(AppContext)
        return (
            <p>
                我是A组件,我的名字是:{ name }<span>我是A的子标签:{ name }</span>
            </p>
        )
    }
    const B= ()=> {
        const { name } = useContext(AppContext);
        return (
            <p>我是B组件,名字是: { name }</p>
        )
    }
    return (
        <AppContext.Provider value={{ name: '张三'}}>
            <A />
            <B />
        </AppContext.Provider>
    )
}
export default HookTest;

子向父传值不仔细介绍,只展示一个例子参考资料4。

3. useEffect:副作用钩子。

类比生命周期函数包括 componentDidMount、componentDidUpdate 和 componentWillUnmount。
具体使用

useEffect(() => { 
      // 在此可以执行任何带副作用操作
      return () => { // 在组件卸载前执行
        // 在此做一些收尾工作, 比如清除定时器/取消订阅等
      }
}, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行

依赖数组stateValue的不同情况:

  1. 没有依赖数组:在组件挂载和每次重新渲染的时候都会执行。
  2. 空数组:在组件挂载的时候执行。
  3. 依赖数组:依赖项发生变化时执行。
4. useReducer:处理状态action钩子。

官网解释:对于拥有许多状态更新逻辑的组件来说,过于分散的事件处理程序可能会令人不知所措。对于这种情况,你可以将组件的所有状态更新逻辑整合到一个外部函数中,这个函数叫作 reducer。

下边是使用useReducer的例子:useReducer可以理解为将状态的变更逻辑全部集成到组件函数外部,函数内部只定义用户做了什么,以及变更的数据或id。

  • 使用useReducer改写前代码:
    App.js
import { useState } from 'react';
import AddTask from './AddTask.js';
import TaskList from './TaskList.js';

export default function TaskApp() {
  //tasks是个list数组
  const [tasks, setTasks] = useState(initialTasks);

  function handleAddTask(text) {
    setTasks([
      ...tasks,
      {
        id: nextId++,
        text: text,
        done: false,
      },
    ]);
  }

  function handleChangeTask(task) {
    setTasks(
      tasks.map((t) => {
        if (t.id === task.id) {
          return task;
        } else {
          return t;
        }
      })
    );
  }

  function handleDeleteTask(taskId) {
    setTasks(tasks.filter((t) => t.id !== taskId));
  }

  return (
    <>
      <h1>布拉格的行程安排</h1>
      <AddTask onAddTask={handleAddTask} />
      <TaskList
        tasks={tasks}
        onChangeTask={handleChangeTask}
        onDeleteTask={handleDeleteTask}
      />
    </>
  );
}

let nextId = 3;
const initialTasks = [
  {id: 0, text: '参观卡夫卡博物馆', done: true},
  {id: 1, text: '看木偶戏', done: false},
  {id: 2, text: '打卡列侬墙', done: false},
];

  • 使用useReducer改写后代码:
    App.js
import { useReducer } from 'react';
import AddTask from './AddTask.js';
import TaskList from './TaskList.js';
import tasksReducer from './tasksReducer.js';

export default function TaskApp() {

  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);

  function handleAddTask(text) {
    dispatch({
      type: 'added',
      id: nextId++,
      text: text,
    });
  }

  function handleChangeTask(task) {
    dispatch({
      type: 'changed',
      task: task,
    });
  }

  function handleDeleteTask(taskId) {
    dispatch({
      type: 'deleted',
      id: taskId,
    });
  }

  return (
    <>
      <h1>布拉格的行程安排</h1>
      <AddTask onAddTask={handleAddTask} />
      <TaskList
        tasks={tasks}
        onChangeTask={handleChangeTask}
        onDeleteTask={handleDeleteTask}
      />
    </>
  );
}

let nextId = 3;
const initialTasks = [
  {id: 0, text: '参观卡夫卡博物馆', done: true},
  {id: 1, text: '看木偶戏', done: false},
  {id: 2, text: '打卡列侬墙', done: false},
];
  • tasksReducer.js
export default function tasksReducer(tasks, action) {
  switch (action.type) {
    case 'added': {
      return [
        ...tasks,
        {
          id: action.id,
          text: action.text,
          done: false,
        },
      ];
    }
    case 'changed': {
      return tasks.map((t) => {
        if (t.id === action.task.id) {
          return action.task;
        } else {
          return t;
        }
      });
    }
    case 'deleted': {
      return tasks.filter((t) => t.id !== action.id);
    }
    default: {
      throw Error('未知 action:' + action.type);
    }
  }
}

5. userRef:DOM操作钩子。

主要用于获取组件中的 dom 对象,来操作 DOM。但是实际上它可以保存任何值。

const ref = useRef(initialValue) 

userRef返回一个只有一个属性 current 的对象,current 初始值为 initialValue。之后可以将其设置为其他值。如果将 ref 传递给一个 JSX 节点的 ref 属性,React 将为它设置 current 属性。
改变 ref.current 属性时,React 不会重新渲染组件。

例子1:用于操作DOM节点

import { useRef } from 'react';

export default function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        聚焦输入框
      </button>
    </>
  );
}

例子2:使用 useRef 来保存不需要变化的值
因为 useRef 的返回值在组件的每次 render 之后都是同一个,所以它可以用来保存一些在组件整个生命周期都不需要变化的值。最常见的就是定时器的清除场景。

const App = () => {
  const timer = useRef();
  useEffect(() => {
    timer.current = setInterval(() => {
      console.log('触发了');
    }, 1000);
  },[]);
  const clearTimer = () => {
    clearInterval(timer.current);
  }
  return (
    <>
      <Button onClick={clearTimer}>停止</Button>
    </>)
}
6. userMemo:数据缓存钩子。

它在每次重新渲染的时候能够缓存计算的结果。为了优化组件渲染的性能问题,有时候父组件重新渲染子组件不需要重新渲染,如果子组件的逻辑较复杂,就是无意义的大量计算,浪费资源。
useMemo 用于对计算成本较高的值进行记忆化处理,以提高性能。

在下边的示例中,useMemo 缓存了计算结果 a + b,并且只有当 a 或 b 的值发生变化时,才会重新计算结果。这样可以避免在每次组件渲染时都执行成本较高的计算操作。expensiveValue 没有变化的时候,即使父组件重新渲染了,子组件也不会重新渲染。

当需要对大量的数据进行处理和转换时,比如从服务器获取的原始数据需要进行筛选、排序、格式化等操作,这些计算都会耗费一定的时间。通过使用 useMemo 缓存处理后的数据,可以避免在每次组件渲染时都执行这些计算,提高页面性能。

import React, { useMemo } from 'react';

function ExpensiveComponent({ a, b }) {
  const expensiveValue = useMemo(() => {
    //计算成本较高操作
    console.log('Compute expensive value');
    return a + b;
  }, [a, b]); // 只有在 a 或 b 发生变化时才重新计算值

  return <div>{expensiveValue}</div>;
}

7. useCallBack:函数缓存钩子。

useMemo 是对数据的记忆,useCallback 是对函数的记忆。

在下边的示例中,useCallback 缓存了 handleClick 回调函数,并且只有在 count 的值发生变化时才会重新创建函数实例。这样可以避免在每次父组件渲染时都创建新的函数实例,提高性能。

import React, { useCallback, useState } from 'react';

function ParentComponent() {
  const [count, setCount] = useState(0);

  // 使用 useCallback 缓存回调函数,只在 count 发生变化时才重新创建函数实例
  const handleClick = useCallback(() => {
    console.log('Button clicked');
  }, [count]);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
      <ChildComponent onClick={handleClick} />
    </div>
  );
}

function ChildComponent({ onClick }) {
  return <button onClick={onClick}>Click me</button>;
}

其他参考资料:

1.HTML模板语法:

1.1 变量插值使用占位符插入变量的值。例如:

<p>{{ variable }}</p>

1.2 条件语句
条件语句根据条件显示或隐藏特定的内容。例如:

{% if condition %}
  <!-- 内容 -->
{% else %}
  <!-- 其他内容 -->
{% endif %}

1.3 循环遍历
循环遍历用于在模板中遍历数组或字典等数据结构。例如:

{% for i in list %}
  <li>{{ i }}</li>
{% endfor %}

参考: link.

2.自定义 Hook:

在React中,自定义Hook是一个函数,其名称以"use"开头,并可以在函数组件中使用。自定义Hook可以帮助我们封装和复用状态逻辑和副作用代码。

以下是一个简单的自定义Hook的例子,它用于追踪组件的挂载状态:

import { useState, useEffect, useRef } from 'react';
 
function useMountedState() {
  const [isMounted, setIsMounted] = useState(false);
  const isMountedRef = useRef(isMounted);
 
  useEffect(() => {
    isMountedRef.current = true;
    return () => {
      isMountedRef.current = false;
    };
  }, []);
 
  const getIsMounted = () => isMountedRef.current;
 
  return { isMounted: getIsMounted };
}
 
export default useMountedState;

使用这个自定义Hook的方法如下:

import useMountedState from './useMountedState';
 
function MyComponent() {
  const { isMounted } = useMountedState();
 
  // 使用isMounted函数来判断组件是否挂载
  useEffect(() => {
    if (isMounted()) {
      // 组件处于挂载状态,执行一些操作
    }
  }, []);
 
  return (
    <div>
      {/* 组件的内容 */}
    </div>
  );
}

3.react的Fiber 架构:

这是一种全新的协调引擎,旨在提高 React 应用的性能,尤其是在复杂和高频更新的场景下。可以理解为是一个更强大的虚拟DOM。
Fiber工作原理中最核心的点就是:可以中断和恢复,这个特性增强了React的并发性和响应性。
参考: link.

4.react的子向父传值:

夫组件:

import React from 'react';
import ChildComponent from './ChildComponent';
 
const ParentComponent = () => {
  const handleChildData = (data) => {
    console.log('从子组件接收的数据:', data);
  };
 
  return (
    <ChildComponent onDataFromChild={handleChildData} />
  );
};
 
export default ParentComponent;

子组件:

import React from 'react';
 
const ChildComponent = ({ onDataFromChild }) => {
  const sendDataToParent = () => {
    const data = '这是子组件的数据';
    onDataFromChild(data);
  };
 
  return (
    <button onClick={sendDataToParent}>点击传值给父组件</button>
  );
};
 
export default ChildComponent;

5.副作用和纯函数:

副作用是和纯函数相关的一个词,纯函数是指函数执行过程中,只有返回值,它的过程中不会让外部环境产生变化:包括但不限于修改外部变量、状态、发送网络请求、操作 DOM 等。它们只依赖于传入的参数,并且仅根据参数的值来计算返回值。
而且给定相同的输入,纯函数总是返回相同的输出,不受外部环境或状态的影响。

而副作用就是函数执行过程中,对外部环境进行的操作,在前端项目中例如数据请求等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值