React的基本知识与常见hooks的用法

1. 渲染一个基本组件

以下一个小demo用来展示第一个用react语法来编写的组件

// main文件
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
  // 父子组件单向传递
  <App type="text"/>
);
function App({ type }: { type: string }){
  const h1 = <h1>react后台管理</h1>;
	const list = ["tom", "Jack", "Lucy", "Lily"];
	const style = { color: "pink", fontSize: "16px" };
	const value = "123";
  const title = "标题1"
  return (
    <div className="APP">
      {h1}
			<div>
        // 在JSX中使用可以使用大括号编辑javaScript
				{list.map((item) => (
					<span key={item} style={style}>
						{item}
					</span>
				))}
			</div>
			<div>{title}</div>
			<div>
				<div>用户名称:{user.name}</div>
				<div>用户性别:{user.gender}</div>
			</div>
			<input type={type} value={value}></input>
    </div>
    )
}
export default App;

React的基本知识与常见hooks的用法

2. 常见hooks的用法

2.1 useState

语法定义:

const [state, dispatch] = useState(initData);

state: 定义的数据源,可视作一个函数组件内部的变量,但只在首次渲染被创造。

dispatch: 改变state的函数,推动函数渲染的渲染函数,即会进行触发=>渲染=>提交三步骤。dispacth有两种情况-非函数和函数。

initData: state的初始值,initData有两种情况-非函数和函数。

function App({ type }: { type: string }){
  const h1 = <h1>react后台管理</h1>;
	const list = ["tom", "Jack", "Lucy", "Lily"];
	const style = { color: "pink", fontSize: "16px" };
	const value = "123";
	let condition = 2;
	const [user, setUser] = useState({
		name: "terrence",
		gender: "male",
	});
	const [title, setTitle] = useState("标题1");
	const changeTitle = () => {
		setTitle("标题2");
	};
	const changeUserName = () => {
		// 当要修改一个数组或对象中的某个元素或属性时,
    // 需要使用展开运算符进行浅拷贝,最后修改需要修改的属性
		setUser({ ...user, name: "Bob" });
	};
	const changeUser = () => {
		setUser({ name: "Lily", gender: "female" });
	};
  return (
    <div className="APP">
      {h1}
			<div>
        // 在JSX中使用可以使用大括号编辑javaScript
				{list.map((item) => (
					<span key={item} style={style}>
						{item}
					</span>
				))}
			</div>
			<div>{title}</div>
			<div>
				<div>用户名称:{user.name}</div>
				<div>用户性别:{user.gender}</div>
			</div>
			<input type={type} value={value}></input>
			<br />
			<div style={{ marginTop: "10px" }}>
				<button onClick={changeTitle}>修改标题</button>
				<button onClick={changeUserName}>修改用户名称</button>
				<button onClick={changeUser}>修改用户</button>
			</div>
    </div>
    )
}
export default App;

如果要进行需要点击按钮后,数字进行加三的操作,则需要将set操作更改为函数形式,因为state如同一张快照,在下一次渲染时,相同的操作会合并为一次操作,因此,可以改变为操作改成函数形式,这样会将操作进行入队,在react下次渲染时,会依次执行队列中的操作。

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      // 每点击一次按钮只会触发一次加一操作
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 1);
        setNumber(number + 1);
        setNumber(number + 1);
      }}>+3</button>
    </>
  )
}

React的基本知识与常见hooks的用法

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        // 修改为函数形式即可变成递增操作
        setNumber(n => n + 1);
        setNumber(n => n + 1);
        setNumber(n => n + 1);
      }}>+3</button>
    </>
  )
}

2.2 useEffect

语法定义:

useEffect(setup, dependenices)

setup: 是用来处理Effect函数。setup函数会选择性返回一个清理函数。当组件首次被添加到DOM之前,会执行一次setup函数,在每次依赖项发生变化后,回显执行清理函数,在新DOM渲染时,会再执行一次setup函数。当组件被从DOM中移除,会执行最后一次清理函数。

dependenciese: setup代码中的依赖项。依赖项必须是的固定形式,如[dep1, dep2, dep3]

tips: useEffect是用来模拟了组件的更新这段生命周期。

其中有一些重要的区别如下:

  1. 传递依赖数组时,setup函数会在组件在渲染到DOM上时,会执行一次,当依赖项发生了变化时,会重新执行一次。
  2. 传递空数组时,setup函数只会在组件渲染到DOM上之前执行一次。
  3. 不传递依赖项时,setup函数会在组件每次渲染时,执行一次。

以下是使用useEffect来监听窗口变化大小

import { useState, useEffect } from "react";
export function useWindowSize() {
	const [size, setSize] = useState({
		// 整个屏幕的宽高
		width: document.documentElement.clientWidth,
		height: document.documentElement.clientHeight,
	});
	const handleResize = () => {
		setSize({
			width: document.documentElement.clientWidth,
			height: document.documentElement.clientHeight,
		});
	};
	useEffect(() => {
		// 注意凡是监听全局全局变量的改变的一定要卸载
		// 防止内存泄漏
		window.addEventListener("resize", handleResize);
		return () => {
			window.removeEventListener("resize", handleResize);
		};
	}, []);
	return [size];
}

2.3 useRef

语法:

const ref = useRef(initialValue)
  • initialValue:ref 对象的 current 属性的初始值。可以是任意类型的值。这个参数会首次渲染后被忽略。

返回值:

useRef 返回一个只有一个属性的对象:

  • current:最初,它被设置为你传递的 initialValue。之后你可以把它设置为其他值。如果你把 ref 对象作为一个 JSX 节点的 ref 属性传递给 React,React 将为它设置 current 属性。

在后续的渲染中,useRef 将返回同一个对象。

用法

import { useRef, useState } from 'react'
import './App.css'

function App() {
  const userRef = useRef<HTMLInputElement>(null)
  const [val, setVal] = useState('')
  const handleClick = () => {
    userRef.current?.focus()
    setVal(userRef.current?.value || '')
  }
  return (
    <div className='App'>
      <input type='text' ref={userRef} />
      <button onClick={handleClick}>按钮</button>
      <p>{val}</p>
    </div>
  )
}

export default App

2.4 useContext

语法:

const value = useContext(SomeContext)
  • SomeContext:先前用 createContext 创建的 context。context 本身不包含信息,它只代表你可以提供或从组件中读取的信息类型。

用法:

// App.tsx
const UserContext = React.createContext({ name: '' })
function App() {
  return (
    <UserContext.Provider value={{ name: 'jack' }}>
      <div>
        <p>欢迎学习React后台课程</p>
        <Child1 />
      </div>
    </UserContext.Provider>
  )
}

function Child1() {
  return (
    <div>
      <p>
        <span>Child1</span>
      </p>
      <p>
        <Child2 />
      </p>
    </div>
  )
}

function Child2() {
  const { name } = useContext(UserContext)
  return <span>Child2{name}</span>
}

2.5 useTransition

useTransition 是一个让你在不阻塞 UI 的情况下来更新状态的 React Hook。

语法:

const [isPending, startTransition] = useTransition()

参数

useTransition 不需要任何参数。

返回值

useTransition 返回一个由两个元素组成的数组:

  1. isPending 标志,告诉你是否存在待处理的转换。
  2. startTransition函数 允许你将状态更新标记为转换状态。
function App(){
  const [query, setQuery] = useState('');
	const [sequence, setSequence] = useState([]);
	const [isPending, startTransition] = useTransition();
	const handleInputChange = (e: any) => {
		setQuery(e.target.value)
		startTransition(() => {
			const arr = Array.from({ length: 1000 }).fill(1);
			setSequence([...sequence, ...arr]);
		})
	}
  return (
    <div>transition的用法</div>
			<input type="text" onChange={handleInputChange} value={query}></input>
			<div>
				{isPending ?
					(<div>lOADING...</div>)
					:
					sequence.map((item: number, index: number) => {
						return <div key={index}>{item}</div>
					})
				}
			</div>
    )
}

3. 与Vue.js的比较

3.1 大致的比较

React的基本知识与常见hooks的用法

3.2 diff算法实现的比较

vue中diff算法实现流程:

  1. 在内存中构建虚拟dom树
  2. 将内存中虚拟dom树渲染成真实dom结构
  3. 数据改变的时候,将之前的虚拟dom树结合新的数据生成新的虚拟dom树
  4. 将此次生成好的虚拟dom树和上一次的虚拟dom树进行一次比对(diff算法进行比对),来更新只需要被替换的DOM,而不是全部重绘。在Diff算法中,只平层的比较前后两棵DOM树的节点,没有进行深度的遍历。
  5. 会将对比出来的差异进行重新渲染。

react中diff算法实现流程:

  1. DOM结构发生改变—–直接卸载并重新create
  2. DOM结构一样—–不会卸载,但是会update变化的内容
  3. 所有同一层级的子节点.他们都可以通过key来区分—–同时遵循1.2两点
    (其实这个key的存在与否只会影响diff算法的复杂度,换言之,你不加key的情况下,diff算法就会以暴力的方式去根据一二的策略更新,但是你加了key,diff算法会引入一些另外的操作)

3.3 Vue和React生命周期

Vue:

初始化阶段:

  1. beforeCreate()
  2. created():已经挂载了数据,但是dom节点没有渲染。此阶段可以发送一些ajax请求与初始化事件。
  3. beforeMount()
  4. mounted():数据已经挂载完毕,可以获取到真实的dom。

运行中的阶段:

  1. beforeUpdate():这个阶段获取到的数据是dom内容更新前的数据。此阶段应该避免对数据的更改,会造成死循环。
  2. updated():可以获取到更新过后的数据,当数据触发重新渲染时,可以在updated函数中获取真实的dom元素。

销毁阶段:

  1. beforeDestroy:这个钩子,可以在组件被销毁前,做一些清除工作,比如定时器,窗口大小发生变化的绑定事件。
  2. destroyed:这个阶段组件只有真实dom存在在页面中

其他:

  1. 被keep-alive包裹的组件会有active与deacive两个生命周期,因为组件不会被销毁,组件会在活动与失活之间的状态切换。
React:

react组件的生命周期主要分为四个阶段:

  1. 初始化阶段:初始化属性props和状态state。
  2. 挂载阶段:将组建挂载到页面上。
  3. 更新阶段:当组件中的props和state发生变化会进行更新。
  4. 卸载阶段:组件从页面中删除。

React的基本知识与常见hooks的用法

4. 参考资料

  1. react中文文档:react.docschina.org/learn
  2. react慕课网入门教程:coding.imooc.com/class/644.h…

原文链接:https://juejin.cn/post/7265937125000970274 作者:NobodyDJ

(0)
上一篇 2023年8月12日 上午10:56
下一篇 2023年8月12日 上午11:07

相关推荐

发表回复

登录后才能评论