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
主要用途 用于记忆计算结果 用于记忆定义函数
返回值 返回计算结果 返回记忆函数
使用场景 避免昂贵的计算 避免不必要的子组件重新渲染
相关推荐
Dontla3 小时前
n8n飞书webhook配置(飞书机器人、飞书bot、feishu bot)Crypto节点、js timestamp代码、Crypto node
javascript·机器人·飞书
tager4 小时前
🔥3行代码搞定全局代理!告别插件依赖的极简方案
前端·fiddler·charles
gnip5 小时前
axios 拦截器实现用户无感刷新 access_token
前端
程序员码歌5 小时前
【零代码AI编程实战】AI灯塔导航-成果展示篇
前端·ai编程·cursor
gnip6 小时前
前端实现即时通讯,常用的技术
前端
烛阴6 小时前
告别 any!用联合类型打造更灵活、更安全的 TS 代码
前端·typescript
excel7 小时前
全面解析 JavaScript 类继承:方式、优缺点与应用场景
前端
用户21411832636027 小时前
dify案例分享-100% 识别率!发票、汇票、信用证全搞定的通用票据识别工作流
前端
Hello.Reader8 小时前
Elasticsearch JS 客户端子客户端(Child Client)实践指南
大数据·javascript·elasticsearch
拾光拾趣录8 小时前
基础 | HTML语义、CSS3新特性、浏览器存储、this、防抖节流、重绘回流、date排序、calc
前端·面试