react(基础篇)

React由Meta公司研发,用于构建Web和原生交互界面的库。

React 官方中文文档

查看JSX

(一)React组件

  • 用户界面的一部分,通俗的来讲,最小的元素组成的单元,可以实现部分逻辑与功能

  • 房子的门就可以看成一个组件,由木板和木方组成,有一定功能和作用,多个组件组合就可以形成房子了。

  • 组件之间可以相互嵌套,重复使用

React组件

  • React中,组件就是一个首字母大写的函数,内部存放组件的逻辑和视图UI,使用组件只需将组件当成标签写即可

  • 组件也不能返回多个 JSX 标签,必须将它们包裹到一个共享的父级中,比如 <div>...</div> 或使用空的 <>...</> 包裹:

  • 组件只负责自己的任务。 它不会更改在该函数调用前就已存在的对象或变量。

  • 组件输入相同,则输出相同。 给定相同的输入,组件应该总是返回相同的 JSX。

js 复制代码
function MyButton() {
    return(
        <button >点了我</button>
    );
}

const App = () => {

    return <MyButton ></MyButton>;

};

Hook(钩子函数)

hook是特殊的函数,搭配函数组件一起使用,使其功能更强大

hook使用规则

  • 只能在顶层调用Hooks,不要在循环、条件判断或者嵌套函数中调用。
  • 只能在React函数组件或自定义Hook中调用Hooks。

(二)useState

为组件设置state可以让组件拥有记忆,完成交互

特点

  • State 变量 用于保存渲染间的数据。

  • State setter 函数 更新变量并触发 React 再次渲染组件

  • 只能在组件或[自定义 Hook]的最顶层调用

快速入门

  1. 在文件顶部导入useState

    js 复制代码
    import { useState } from 'react';
  2. 创建一个useState

    js 复制代码
    const [index, setIndex] = useState(0);

    useState 的唯一参数是 state 变量的初始值

useState细节理解

  1. 状态更新是异步的

    React 会将多个状态更新合并,以提高性能。因此,状态更新不会立即生效,而是会在下一次渲染时生效。

  2. 批量更新

    在 React 的事件处理函数中,多个状态更新会被批量处理,只触发一次重新渲染。

useState更新原理

State通过setState更新,实际上State只是可读的,setState更新只是将原来的值替换掉,而并非修改原数据

  1. 更新State对象

    通过...对象展开符快速跟新对象

    js 复制代码
    const [user, setUser] = useState({ name: 'Alice', age: 25 });
    
    // 更新年龄
    const updateAge = () => {
      setUser(prev => ({ ...prev, age: 26 }));
    };
  2. 更新State数组

    注意:即使你拷贝了数组,你还是不能直接修改其内部的元素,因为数组拷贝是浅拷贝

    避免使用 (会改变原始数组) 推荐使用 (会返回一个新数组)
    添加元素 pushunshift concat[...arr] 展开语法
    删除元素 popshiftsplice filterslice
    替换元素 splicearr[i] = ... 赋值 map
    排序 reversesort 先将数组复制一份,再排序

受控表单

使用react组件状态控制表单

js 复制代码
const App = () => {

    const [value, setValue] = useState('');
    return (
        <>
            <input
                value={value}
                onChange={(e)=>setValue(e.target.value)}
                type="text"

            />
        </>
    )
};

如何构建State

  1. 先根据react数据驱动视图的特点,页面哪些UI状态改变会导致界面改变,就给它定义个State控制界面更新
  2. 然后根据构建State原则对State进行优化

构建State的原则

状态提升

要从多个子组件收集数据,或让两个子组件相互通信,请改为在其父组件中声明共享 state。父组件可以通过 props 将该 state 传回给子组件。这使子组件彼此同步并与其父组件保持同步。

(三)props

React中使用props进行参数传递

js 复制代码
//value=0进行默认赋值,当value=null就读取默认值0
function Square({value=0, onSquareClick}) {

    return (
        <button className="square" onClick={onSquareClick}>{value}</button>
    );
}

export default function App(){
    
    return(
    	<div className="board-row">
                <Square value="1" onSquareClick={() => handleClick(0)}/>
                <Square value="2" onSquareClick={() => handleClick(1)}/>
                <Square value="3" onSquareClick={() => handleClick(2)}/>
        </div>
    );
}

children属性

props.children 是一个特殊的属性,用于传递组件包裹的子元素(子节点)

children 可以是以下任意类型:

  • 字符串:直接作为文本内容。
  • React 元素 :如 <div>、自定义组件等。
  • 数组:多个子元素组成的数组。
  • 函数 :通过函数模式实现动态渲染(即 Render Props 模式)。
  • 空值nullundefinedfalse(不会被渲染)。
js 复制代码
<Child>
  <h1>标题</h1>
  <p>段落</p>
</Child>

// Child 组件内部:
function Child(props) {
  return <div>{props.children}</div>; // 同时渲染标题和段落
}

(四)UseContext跨层传递参数

Context是一种跨组件层级传递数据的机制,适合全局数据(如用户信息、主题、语言等),区别于props逐层传递。

  • Provider :通过 <MyContext.Provider value={data}> 向子组件树传递数据。
  • Consumer :通过 useContext(MyContext) 直接获取最近一层 Provider 提供的数据。

示例

假设有 3 层组件:ParentChildGrandchild,需要将用户信息从 Parent 直接传递到 Grandchild,无需经过 Child 中转。

js 复制代码
// UserContext.js
import { createContext } from 'react';

export const UserContext = createContext({ 
  name: '默认用户', 
  age: 0 
});
js 复制代码
// Parent.jsx
import { UserContext } from './UserContext';
import Child from './Child';

const Parent = () => {
  const user = { 
    name: "小明", 
    age: 20 
  };

  return (
    <UserContext.Provider value={user}>
      <div>
        <h2>Parent 组件</h2>
        <Child /> {/* 子组件不需要传递任何 props! */}
      </div>
    </UserContext.Provider>
  );
};
js 复制代码
// Child.jsx
import Grandchild from './Grandchild';

const Child = () => {
  return (
    <div>
      <h3>Child 组件</h3>
      <Grandchild /> {/* 同样无需传递 props */}
    </div>
  );
};
js 复制代码
// Grandchild.jsx
import { useContext } from 'react';
import { UserContext } from './UserContext';

const Grandchild = () => {
  const user = useContext(UserContext); // 直接获取数据

  return (
    <div>
      <h4>Grandchild 组件</h4>
      <p>用户名:{user.name}</p>
      <p>年龄:{user.age}</p>
    </div>
  );
};

(五)UseReducer集中状态管理

useReducer -- React 中文文档

js 复制代码
const [state, dispatch] = useReducer(reducer, initialState)

useReducer类似useState管理组件状态,而UseReudcer集中状态管理,管理方式类似"告诉reducer函数用户进行了什么操作"

参数

  • initialState:初始化状态
  • reducer函数:负责集中管理更新状态(组件状态更新就是在这里面)

返回值

  • state:目前状态
  • dispatch函数:主要负责记录用户进行了什么操作并记录值,比如点击更新按钮、点击删除按钮等

如何将State状态迁移至Reducer中

用State进行状态管理的Todo清单

js 复制代码
function TodoList() {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState('');

  const addTodo = () => {
    setTodos([...todos, input]);
    setInput('');
  };

  return (
    <div>
      <input
        type="text"
        value={input}
        onChange={(e) => setInput(e.target.value)}
      />
      <button onClick={addTodo}>Add Todo</button>
      <ul>
        {todos.map((todo, index) => (
          <li key={index}>{todo}</li>
        ))}
      </ul>
    </div>
  );
}

用Reducer进行状态管理的Todo清单

js 复制代码
const initialState = {
  todos: [],
  input: '',
};

function reducer(state, action) {
  switch (action.type) {
    case 'updateInput':
      return { ...state, input: action.payload };
    case 'addTodo':
      return { ...state, todos: [...state.todos, state.input], input: '' };
    default:
      return state;
  }
}

function TodoList() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <input
        type="text"
        value={state.input}
        onChange={(e) => dispatch({ type: 'updateInput', payload: e.target.value })}
      />
      <button onClick={() => dispatch({ type: 'addTodo' })}>Add Todo</button>
      <ul>
        {state.todos.map((todo, index) => (
          <li key={index}>{todo}</li>
        ))}
      </ul>
    </div>
  );
}

(六)性能提升

React.memo

用memo包裹的组件拥有记忆缓存,当props没有改变该组件不会重新渲染

js 复制代码
React.memo(function MyComponent(props){},可选参数)

特点

  • props与上一次相同(是同一个),如果props是对象或者数组,重新创建一个相同的新的,React也会认为不同,所以通常useMemo、useCallback一起使用
  • useContext多层传参也会导致Memo包裹的组件重新渲染,所以一般在外层接收作为props传入

useMemo

useMemo(函数,依赖数组),useMemo组成通常是函数和依赖数组,可以在每次重新渲染缓存计算结果(函数的返回值)

  • 函数是任意不带参的函数(一般用箭头函数),可返回任意值

  • 依赖数组:一般是props或useState

js 复制代码
const TodoList=useMemo(()=>todo(tab,list),[tab,list])

useCallback

useCallback用来缓存函数,当依赖数组不发生改变时,函数不变,效果类似useMemo

js 复制代码
useCallback(fn,dependencies)

区别useMemo和useCallback

区别 useMemo useCallback
主要用途 用于记忆计算结果 用于记忆定义函数
返回值 返回计算结果 返回记忆函数
使用场景 避免昂贵的计算 避免不必要的子组件重新渲染
相关推荐
lvchaoq10 分钟前
页面停留时间过长导致token过期问题
前端
兔老大的胡萝卜12 分钟前
pm2 部署nuxt4项目
javascript·nuxt4
阿蒙Amon15 分钟前
JavaScript学习笔记:17.闭包
javascript·笔记·学习
elangyipi12315 分钟前
深入理解前端项目中的 package.json 和 package-lock.json
前端·json
Wpa.wk17 分钟前
自动化测试 - 文件上传 和 弹窗处理
开发语言·javascript·自动化测试·经验分享·爬虫·python·selenium
l1t19 分钟前
利用小米mimo为精确覆盖矩形问题C程序添加打乱函数求出更大的解
c语言·开发语言·javascript·人工智能·算法
LYFlied27 分钟前
【算法解题模板】-【回溯】----“试错式”问题解决利器
前端·数据结构·算法·leetcode·面试·职场和发展
composurext28 分钟前
录音切片上传
前端·javascript·css
程序员小寒28 分钟前
前端高频面试题:深拷贝和浅拷贝的区别?
前端·javascript·面试
狮子座的男孩33 分钟前
html+css基础:07、css2的复合选择器_伪类选择器(概念、动态伪类、结构伪类(核心)、否定伪类、UI伪类、目标伪类、语言伪类)及伪元素选择器
前端·css·经验分享·html·伪类选择器·伪元素选择器·结构伪类