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
主要用途 用于记忆计算结果 用于记忆定义函数
返回值 返回计算结果 返回记忆函数
使用场景 避免昂贵的计算 避免不必要的子组件重新渲染
相关推荐
Qrun42 分钟前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp43 分钟前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.2 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl4 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫5 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友5 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理7 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻7 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
mapbar_front8 小时前
在职场生存中如何做个不好惹的人
前端
牧杉-惊蛰8 小时前
纯flex布局来写瀑布流
前端·javascript·css