React框架学习文档(二)

三. 数据层面

目录

[3.1 基础数据](#3.1 基础数据)

[3.1.1 State(状态)](#3.1.1 State(状态))

拓展内容------类组件VS函数组件

[3.1.2 Props(属性)](#3.1.2 Props(属性))

[3.2 组件通信](#3.2 组件通信)

[3.2.1 父组件向子组件通信------props](#3.2.1 父组件向子组件通信——props)

[3.2.2 子组件向父组件通信------回调函数](#3.2.2 子组件向父组件通信——回调函数)

[3.2.3 兄弟组件通信------以父为中介](#3.2.3 兄弟组件通信——以父为中介)

[3.2.4 跨级组件通信------context API | Redux](#3.2.4 跨级组件通信——context API | Redux)


3.1 基础数据

3.1.1 State(状态)

概念

State是组件内部的数据存储,用于管理组件的动态数据和UI状态。

当state发生变化时,React会自动重新渲染组件,确保UI与数据保持同步。

特性
  • 私有性:每个组件的state是独立的,只能在组件内部访问和修改
  • 可变性:state可以随着用户交互或数据变化而改变
  • 响应式:state变化会触发组件重新渲染
  • 异步性:state更新可能是异步的,不能依赖当前state值进行计算
类组件状态管理
javascript 复制代码
import React, { Component } from 'react';

class Counter extends Component {

  // 1. 在constructor中初始化state

  constructor(props) {

    super(props);

    this.state = {

      count: 0,

      message: "初始消息"

    };

  }

  // 2. 通过setState方法更新state

  increment = () => {

    // 正确的更新方式

    this.setState(prevState => ({

      count: prevState.count + 1

    }));

    // 错误的更新方式(依赖当前state值)

    // this.setState({ count: this.state.count + 1 });

  };

  changeMessage = () => {

    this.setState({

      message: "消息已更新"

    });

  };

  render() {

    return (

      <div>

        <h1>计数器: {this.state.count}</h1>

        <p>{this.state.message}</p>

        <button onClick={this.increment}>增加</button>

        <button onClick={this.changeMessage}>更新消息</button>

      </div>

    );

  }

}

export default Counter;
函数组件状态管理(使用useState Hook)
javascript 复制代码
import React, { useState } from 'react';

function Counter() {

  // 1. 使用useState Hook初始化state

  const [count, setCount] = useState(0);

  const [message, setMessage] = useState("初始消息");

  // 2. 更新state的函数

  const increment = () => {

    // 正确的更新方式

    setCount(prevCount => prevCount + 1);

    // 也可以直接使用

    // setCount(count + 1);

  };

  const changeMessage = () => {

    setMessage("消息已更新");

  };

  return (

    <div>

      <h1>计数器: {count}</h1>

      <p>{message}</p>

      <button onClick={increment}>增加</button>

      <button onClick={changeMessage}>更新消息</button>

    </div>

  );

}

export default Counter;
State更新注意事项
  1. 不要直接修改state:this.state.count = 1; 是错误的
  2. 使用setState更新:this.setState({ count: 1 });
  3. 函数式更新:当新state依赖于旧state时,使用函数式更新
  4. 批量更新:React会批量处理state更新,提高性能
拓展内容------类组件VS函数组件
函数组件
javascript 复制代码
// 函数组件 - 简单的JavaScript函数

function Welcome(props) {

  return <h1>Hello, {props.name}</h1>;

}
类组件
javascript 复制代码
// 类组件 - 继承自React.Component

class Welcome extends React.Component {

  render() {

    return <h1>Hello, {this.props.name}</h1>;

  }

}
核心区别对比

|-----------------|------------------|---------------------|
| 特性 | 函数组件 | 类组件 |
| 定义方式 | JavaScript函数 | ES6类继承 |
| 状态管理 | 通过useState Hook | 通过this.state |
| 生命周期 | 通过useEffect Hook | 通过生命周期方法 |
| this 指向 | 无this | 有this |
| 代码复杂度 | 简洁 | 样板代码较多 |
| 性能 | 通常更优 | 开销较大 |
| 逻辑复用 | 通过自定义Hook | 通过高阶组件或render props |

状态管理差异

函数组件(使用Hooks):

javascript 复制代码
import React, { useState } from 'react';

function Counter() {

  // 使用useState Hook管理状态

  const [count, setCount] = useState(0);

  return (

    <div>

      <p>计数: {count}</p>

      <button onClick={() => setCount(count + 1)}>增加</button>

    </div>

  );

}

类组件:

javascript 复制代码
import React, { Component } from 'react';

class Counter extends Component {

  // 在constructor中初始化state

  constructor(props) {

    super(props);

    this.state = {

      count: 0

    };

  }

  // 通过setState更新状态

  increment = () => {

    this.setState(prevState => ({

      count: prevState.count + 1

    }));

  };

  render() {

    return (

      <div>

        <p>计数: {this.state.count}</p>

        <button onClick={this.increment}>增加</button>

      </div>

    );

  }

}
生命周期方法差异

函数组件(使用useEffect):

javascript 复制代码
import React, { useState, useEffect } from 'react';

function Timer() {

  const [time, setTime] = useState(0);

  // 模拟componentDidMount和componentDidUpdate

  useEffect(() => {

    const interval = setInterval(() => {

      setTime(prevTime => prevTime + 1);

    }, 1000);

    // 清理函数(模拟componentWillUnmount)

    return () => clearInterval(interval);

  }, []); // 空依赖数组表示只在挂载时执行

  return <div>时间: {time}秒</div>;

}

类组件:

javascript 复制代码
import React, { Component } from 'react';

class Timer extends Component {

  constructor(props) {

    super(props);

    this.state = { time: 0 };

  }

  componentDidMount() {

    this.interval = setInterval(() => {

      this.setState(prevState => ({

        time: prevState.time + 1

      }));

    }, 1000);

  }

  componentWillUnmount() {

    clearInterval(this.interval);

  }

  render() {

    return <div>时间: {this.state.time}秒</div>;

  }

}
为什么现在选择函数组件

(1)函数组件更加简洁,减少了样板代码:

函数组件 - 5行代码

javascript 复制代码
function UserProfile({ user }) {

  return (

    <div>

      <h2>{user.name}</h2>

      <p>{user.email}</p>

    </div>

  );

}

类组件 - 15行代码

javascript 复制代码
class UserProfile extends React.Component {

  render() {

    const { user } = this.props;

    return (

      <div>

        <h2>{user.name}</h2>

        <p>{user.email}</p>

      </div>

    );

  }

}

(2)函数组件通过自定义Hook实现更好的逻辑复用:

自定义Hook - 可复用的状态逻辑

javascript 复制代码
function useCounter(initialValue = 0) {

  const [count, setCount] = useState(initialValue);

  const increment = () => setCount(c => c + 1);

  const decrement = () => setCount(c => c - 1);

  const reset = () => setCount(initialValue);

  return { count, increment, decrement, reset };

}

在多个组件中使用

javascript 复制代码
function Counter1() {

  const { count, increment, decrement } = useCounter();

  return (

    <div>

      <p>计数: {count}</p>

      <button onClick={increment}>+</button>

      <button onClick={decrement}>-</button>

    </div>

  );

}

function Counter2() {

  const { count, increment, decrement, reset } = useCounter(100);

  return (

    <div>

      <p>计数: {count}</p>

      <button onClick={increment}>+</button>

      <button onClick={decrement}>-</button>

      <button onClick={reset}>重置</button>

    </div>

  );

}

(3)函数组件具有更好的性能表现:

  1. 更小的内存占用:函数组件不需要实例化,直接执行函数
  2. 更快的渲染:React可以更有效地优化函数组件的渲染
  3. 避免不必要的重新渲染:通过useMemo和useCallback可以更好地控制渲染

(4)函数组件的代码更易于阅读和理解:

函数组件 - 逻辑清晰,易于理解

javascript 复制代码
function UserProfile({ user, onUpdate }) {

  const [isEditing, setIsEditing] = useState(false);

  const [name, setName] = useState(user.name);

  useEffect(() => {

    if (!isEditing) {

      setName(user.name);

    }

  }, [user.name, isEditing]);

  const handleSave = () => {

    onUpdate({ ...user, name });

    setIsEditing(false);

  };

  return (

    <div>

      {isEditing ? (

        <input

          value={name}

          onChange={e => setName(e.target.value)}

          onBlur={handleSave}

        />

      ) : (

        <h2 onClick={() => setIsEditing(true)}>{name}</h2>

      )}

    </div>

  );

}

(5)函数组件是React的未来发展方向:

  1. 持续更新:React团队持续为函数组件添加新特性
  2. Hooks生态:丰富的Hooks生态系统支持各种复杂场景
  3. TypeScript友好:函数组件与TypeScript结合更加自然
优先使用函数组件的情况
  1. 展示型组件(无状态或简单状态)
  2. 需要逻辑复用的组件
  3. 性能敏感的组件
  4. 新项目开发
考虑使用类组件的情况
  1. 需要兼容旧版React
  2. 特定场景需要类特性
  3. 复杂的状态管理和生命周期逻辑
  4. 维护现有类组件代码

3.1.2 Props(属性)

概念

Props(Properties的缩写)是父组件向子组件传递数据的方式。

它们是只读的,子组件不能修改props,只能接收和使用。

特性
  • 单向数据流:数据从父组件流向子组件
  • 只读性:子组件不能修改props
  • 灵活性:可以传递任何JavaScript值(字符串、数字、对象、函数等)
  • 默认值:可以通过defaultProps设置默认值
Props使用示例

父组件

javascript 复制代码
import React from 'react';

function ParentComponent() {

  const user = {

    name: "张三",

    age: 25,

    hobbies: ["阅读", "编程", "旅行"]

  };

  return (

    <div>

      <h1>父组件</h1>

      {/* 传递字符串、数字、对象等不同类型的props */}

      <ChildComponent

        name="李四"

        age={30}

        isActive={true}

        user={user}

        onButtonClick={() => alert("按钮被点击了!")}

      />

    </div>

  );

}

子组件

javascript 复制代码
function ChildComponent(props) {

  return (

    <div>

      <h2>子组件</h2>

      <p>姓名: {props.name}</p>

      <p>年龄: {props.age}</p>

      <p>是否活跃: {props.isActive ? "是" : "否"}</p>

      {/* 访问对象props */}

      <p>用户名: {props.user.name}</p>

      <p>年龄: {props.user.age}</p>

      {/* 调用函数props */}

      <button onClick={props.onButtonClick}>点击我</button>

    </div>

  );

}

export default ParentComponent;
Props注意事项

只读性:子组件不能修改props

javascript 复制代码
// 错误的修改方式

props.name = "王五"; // 会抛出错误

默认值设置:

javascript 复制代码
function ChildComponent({ name = "默认名称", age = 18 }) {

  return <div>{name} - {age}</div>;

}

// 或者使用defaultProps

ChildComponent.defaultProps = {

  name: "默认名称",

  age: 18

};

类型检查(使用PropTypes):

javascript 复制代码
import PropTypes from 'prop-types';

function ChildComponent({ name, age, isActive }) {

  return (

    <div>

      <p>姓名: {name}</p>

      <p>年龄: {age}</p>

      <p>是否活跃: {isActive ? "是" : "否"}</p>

    </div>

  );

}

ChildComponent.propTypes = {

  name: PropTypes.string.isRequired,

  age: PropTypes.number,

  isActive: PropTypes.bool

};

3.2 组件通信

3.2.1 父组件向子组件通信------props

概念

父组件通过props将数据传递给子组件,子组件接收这些props并在内部使用。

示例

父组件

javascript 复制代码
import React from 'react';

function ParentComponent() {

  const [message, setMessage] = useState("欢迎来到React世界!");

  const [count, setCount] = useState(0);

  return (

    <div>

      <h1>父组件</h1>

      <p>当前计数: {count}</p>

      {/* 传递数据给子组件 */}

      <ChildComponent

        message={message}

        count={count}

        onIncrement={() => setCount(count + 1)}

      />

    </div>

  );

}

子组件

javascript 复制代码
function ChildComponent({ message, count, onIncrement }) {

  return (

    <div>

      <h2>子组件</h2>

      <p>{message}</p>

      <p>接收的计数: {count}</p>

      <button onClick={onIncrement}>增加计数</button>

    </div>

  );

}

export default ParentComponent;
特点
  1. 简单直接,是React中最常用的通信方式
  2. 适用于父子组件层级较近的情况
  3. 数据流向清晰,易于理解和维护

3.2.2 子组件向父组件通信------回调函数

概念

子组件通过调用父组件传递的回调函数,将数据或事件通知父组件,父组件接收到信息后更新自己的state。

  • 父:
  1. 定义回调函数
  2. Return()中写入子组件标签
  3. 给标签绑定属性并以回调函数为props参数传入
  • 子:
  1. 接收props
  2. 定义变量
  3. 在组件中使用属性传入定义的变量值作参数
示例

父组件

javascript 复制代码
import React, { useState } from 'react';

function ParentComponent() {

  const [childMessage, setChildMessage] = useState("");

  const [childCount, setChildCount] = useState(0);

  // 接收子组件数据的回调函数

  const handleChildMessage = (msg) => {

    setChildMessage(msg);

  };

  const handleChildCount = (count) => {

    setChildCount(count);

  };

  return (

    <div>

      <h1>父组件</h1>

      <p>子组件发送的消息: {childMessage}</p>

      <p>子组件的计数: {childCount}</p>

      {/* 传递回调函数给子组件 */}

      <ChildComponent

        onSendMessage={handleChildMessage}

        onSendCount={handleChildCount}

      />

    </div>

  );

}

子组件

javascript 复制代码
function ChildComponent({ onSendMessage, onSendCount }) {

  const [internalMessage, setInternalMessage] = useState("这是子组件的消息");

  const [internalCount, setInternalCount] = useState(5);

  const sendMessage = () => {

    // 调用父组件的回调函数

    onSendMessage(internalMessage);

  };

  const sendCount = () => {

    onSendCount(internalCount);

  };

  return (

    <div>

      <h2>子组件</h2>

      <p>内部消息: {internalMessage}</p>

      <p>内部计数: {internalCount}</p>

      <button onClick={sendMessage}>发送消息给父组件</button>

      <button onClick={sendCount}>发送计数给父组件</button>

    </div>

  );

}

export default ParentComponent;
特点
  1. 通过回调函数实现双向通信
  2. 父组件控制状态,子组件触发状态更新
  3. 适用于需要子组件通知父组件的场景

3.2.3 兄弟组件通信------以父为中介

概念

当两个组件不是父子关系但有相同的父组件时,称为兄弟组件。

兄弟组件不能直接相互传送数据,需要通过状态提升的方式,将共享状态保存到最近的共同父组件中。

示例

父组件(状态提升)

javascript 复制代码
import React, { useState } from 'react';

function ParentComponent() {

  // 共享状态提升到父组件

  const [sharedMessage, setSharedMessage] = useState("共享消息");

  const [sharedCount, setSharedCount] = useState(0);

  // 提供修改共享状态的函数

  const updateSharedMessage = (msg) => {

    setSharedMessage(msg);

  };

  const updateSharedCount = (count) => {

    setSharedCount(count);

  };

  return (

    <div>

      <h1>父组件(状态提升)</h1>

      <p>共享消息: {sharedMessage}</p>

      <p>共享计数: {sharedCount}</p>

      {/* 两个兄弟组件 */}

      <SiblingComponent1

        sharedMessage={sharedMessage}

        onUpdateMessage={updateSharedMessage}

      />

      <SiblingComponent2

        sharedCount={sharedCount}

        onUpdateCount={updateSharedCount}

      />

    </div>

  );

}

兄弟组件1(send)

javascript 复制代码
function SiblingComponent1({ sharedMessage, onUpdateMessage }) {

  const [localMessage, setLocalMessage] = useState("组件1的消息");

  const sendMessage = () => {

    onUpdateMessage(localMessage);

  };

  return (

    <div style={{ border: '1px solid blue', padding: '10px', margin: '10px' }}>

      <h2>兄弟组件1</h2>

      <p>当前共享消息: {sharedMessage}</p>

      <p>本地消息: {localMessage}</p>

      <button onClick={sendMessage}>发送消息到父组件</button>

      <button onClick={() => setLocalMessage("组件1的新消息")}>更新本地消息</button>

    </div>

  );

}

兄弟组件2(receive)

javascript 复制代码
function SiblingComponent2({ sharedCount, onUpdateCount }) {

  const [localCount, setLocalCount] = useState(10);

  const sendCount = () => {

    onUpdateCount(localCount);

  };

  return (

    <div style={{ border: '1px solid green', padding: '10px', margin: '10px' }}>

      <h2>兄弟组件2</h2>

      <p>当前共享计数: {sharedCount}</p>

      <p>本地计数: {localCount}</p>

      <button onClick={sendCount}>发送计数到父组件</button>

      <button onClick={() => setLocalCount(localCount + 1)}>增加本地计数</button>

    </div>

  );

}

export default ParentComponent;
特点
  1. 通过父组件作为中间人实现兄弟组件通信
  2. 父组件管理共享状态,兄弟组件通过回调函数更新状态
  3. 避免了兄弟组件之间的直接依赖

3.2.4 跨级组件通信------context API | Redux

概念

当组件层级较深时,通过props层层传递数据会导致代码复杂且难以维护,这时可以使用Context API或状态管理库(如Redux)来实现跨级组件通信。

方法1:使用Context API
javascript 复制代码
// 1. 创建Context

import React, { createContext, useContext, useState } from 'react';

// 创建Context

const MessageContext = createContext();

// 2. 父组件提供Context

function GrandparentComponent() {

  const [message, setMessage] = useState("跨级通信消息");

  const [count, setCount] = useState(100);

  return (

    <MessageContext.Provider value={{ message, count, setMessage, setCount }}>

      <h1>祖父组件</h1>

      <ParentComponent />

    </MessageContext.Provider>

  );

}

// 3. 中间组件(不需要传递props)

function ParentComponent() {

  return (

    <div>

      <h2>父组件</h2>

      <ChildComponent />

    </div>

  );

}

// 4. 子组件消费Context

function ChildComponent() {

  // 使用useContext获取Context值

  const { message, count, setMessage, setCount } = useContext(MessageContext);

  return (

    <div style={{ border: '1px solid red', padding: '10px', margin: '10px' }}>

      <h3>子组件</h3>

      <p>从Context获取的消息: {message}</p>

      <p>从Context获取的计数: {count}</p>

      <button onClick={() => setMessage("消息已更新")}>更新消息</button>

      <button onClick={() => setCount(count + 1)}>增加计数</button>

    </div>

  );

}

export default GrandparentComponent;
方法2:使用Redux(状态管理库)
javascript 复制代码
// store.js - 创建Redux store

import { createStore } from 'redux';

// Reducer

function counterReducer(state = { count: 0, message: "Redux消息" }, action) {

  switch (action.type) {

    case 'INCREMENT':

      return { ...state, count: state.count + 1 };

    case 'UPDATE_MESSAGE':

      return { ...state, message: action.payload };

    default:

      return state;

  }

}

// 创建store

const store = createStore(counterReducer);

export default store;

// App.js - 提供store

import React from 'react';

import { Provider } from 'react-redux';

import store from './store';

import GrandchildComponent from './GrandchildComponent';

function App() {

  return (

    <Provider store={store}>

      <div>

        <h1>根组件</h1>

        <GrandchildComponent />

      </div>

    </Provider>

  );

}

export default App;

// GrandchildComponent.js - 任意层级的组件

import React from 'react';

import { useSelector, useDispatch } from 'react-redux';

function GrandchildComponent() {

  // 使用useSelector获取state

  const { count, message } = useSelector(state => state);

  // 使用useDispatch获取dispatch函数

  const dispatch = useDispatch();

  return (

    <div style={{ border: '1px solid purple', padding: '10px', margin: '10px' }}>

      <h3>任意层级的组件</h3>

      <p>计数: {count}</p>

      <p>消息: {message}</p>

      <button onClick={() => dispatch({ type: 'INCREMENT' })}>增加计数</button>

      <button onClick={() => dispatch({ type: 'UPDATE_MESSAGE', payload: '新消息' })}>更新消息</button>

    </div>

  );

}
特点
  1. Context API适用于中等规模的应用,简单易用
  2. Redux适用于大型复杂应用,提供更强大的状态管理
  3. 跨级通信避免了props drilling(props层层传递)
  4. 保持组件的独立性和可复用性
相关推荐
wqwqweee2 小时前
Flutter for OpenHarmony 看书管理记录App实战:个人中心实现
开发语言·javascript·python·flutter·harmonyos
心.c2 小时前
Vue3+Node.js实现文件上传并发控制与安全防线 进阶篇
前端·javascript·vue.js·安全·node.js
pas1362 小时前
36-mini-vue nextTick
前端·javascript·vue.js
冬奇Lab3 小时前
一天一个开源项目(第2篇):Remotion - 用 React 程序化创建视频
react.js·开源·音视频
一条大祥脚4 小时前
势能分析与势能线段树
开发语言·javascript·数据结构·算法
奔跑的web.4 小时前
TypeScript 类型断言
前端·javascript·typescript
ヤ鬧鬧o.4 小时前
HTML多倒计时管理
前端·javascript·css·html5
知兀4 小时前
【uniapp/vue3+ts/js】eslint9+prettier+husky+lint-staged
前端·javascript·uni-app
小北方城市网4 小时前
Spring Cloud Gateway 动态路由进阶:基于 Nacos 配置中心的热更新与版本管理
java·前端·javascript·网络·spring boot·后端·spring