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
主要用途 用于记忆计算结果 用于记忆定义函数
返回值 返回计算结果 返回记忆函数
使用场景 避免昂贵的计算 避免不必要的子组件重新渲染
相关推荐
阿廖沙102416 分钟前
前端不改后端、不开 Node,彻底搞定 Canvas 跨域下载 —— wsrv.nl 野路子实战指南
前端
讨厌吃蛋黄酥16 分钟前
🌟 React Router Dom 终极指南:二级路由与 Outlet 的魔法之旅
前端·javascript
花颜yyds17 分钟前
three.js学习
前端·three.js
SixHateSeven18 分钟前
🚀 TSX动态编译的黑科技,快如闪电!
前端·编译器
aiwery19 分钟前
前端国际化技术实践
前端
兵临天下api44 分钟前
电商数据分析实战:利用 API 构建商品价格监控系统
前端
迷曳1 小时前
32、鸿蒙Harmony Next开发:使用动画-动画概述
前端·华为·动画·harmonyos
FogLetter1 小时前
React中的forwardRef:打破父子组件间的"隔墙"
前端·react.js
专注API从业者1 小时前
自动化商品监控:利用淘宝API开发实时价格库存采集接口
大数据·运维·前端·数据库·数据挖掘·自动化
HappyAcmen1 小时前
HTTP性能优化:打造极速Web体验的关键策略
前端·http·性能优化