React基础学习-Day02

React基础学习-Day02

1.受控表单绑定

在 React 中,受控表单(controlled form)是一种通过 React 组件状态(state)来管理表单元素值的方式。使用受控表单,可以将表单元素的值与 React 组件的状态保持同步,从而实现对表单数据的完全控制和管理。

如何创建受控表单

1. 输入框(Input)

使用 <input> 元素作为例子,展示如何创建一个受控输入框:

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

const ControlledFormExample = () => {
  // 定义一个状态变量来存储输入框的值
  const [inputValue, setInputValue] = useState('');

  // 处理输入框值变化的函数
  const handleInputChange = (event) => {
    setInputValue(event.target.value);  // 更新状态变量的值
  };

  // 提交表单时处理函数
  const handleSubmit = (event) => {
    event.preventDefault();  // 阻止表单默认提交行为
    alert(`Submitted value: ${inputValue}`);  // 弹出输入框的当前值
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Input:
        <input
          type="text"
          value={inputValue}  // 将输入框的值与状态变量绑定
          onChange={handleInputChange}  // 处理输入框值变化的函数
        />
      </label>
      <button type="submit">Submit</button>
    </form>
  );
};

export default ControlledFormExample;
2. 复选框(Checkbox)

对于复选框,需要注意初始状态和处理函数的变化:

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

const CheckboxExample = () => {
  // 定义一个状态变量来存储复选框的选中状态
  const [isChecked, setIsChecked] = useState(false);

  // 处理复选框状态变化的函数
  const handleCheckboxChange = (event) => {
    setIsChecked(event.target.checked);  // 更新状态变量的值
  };

  // 提交表单时处理函数
  const handleSubmit = (event) => {
    event.preventDefault();  // 阻止表单默认提交行为
    alert(`Checkbox checked: ${isChecked}`);  // 弹出复选框的当前选中状态
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Checkbox:
        <input
          type="checkbox"
          checked={isChecked}  // 将复选框的选中状态与状态变量绑定
          onChange={handleCheckboxChange}  // 处理复选框状态变化的函数
        />
      </label>
      <button type="submit">Submit</button>
    </form>
  );
};

export default CheckboxExample;
3. 下拉菜单(Select)

对于 <select> 元素,需要注意选项列表的处理和初始选中值:

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

const SelectExample = () => {
  // 定义一个状态变量来存储选择框的当前选中值
  const [selectedValue, setSelectedValue] = useState('option1');

  // 处理选择框选项变化的函数
  const handleSelectChange = (event) => {
    setSelectedValue(event.target.value);  // 更新状态变量的值
  };

  // 提交表单时处理函数
  const handleSubmit = (event) => {
    event.preventDefault();  // 阻止表单默认提交行为
    alert(`Selected value: ${selectedValue}`);  // 弹出选择框的当前选中值
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Select:
        <select value={selectedValue} onChange={handleSelectChange}>
          <option value="option1">Option 1</option>
          <option value="option2">Option 2</option>
          <option value="option3">Option 3</option>
        </select>
      </label>
      <button type="submit">Submit</button>
    </form>
  );
};

export default SelectExample;

特点和优势

  • 完全控制: 受控表单使得所有表单元素的值都由 React 组件状态管理,可以通过状态更新函数精确控制和验证输入。
  • 一致性和可预测性: 因为状态直接驱动表单元素的值,所以可以确保表单的行为一致和可预测。
  • 验证和处理: 可以轻松实现输入验证、条件渲染和复杂的表单逻辑,例如禁用按钮直到所有必填字段都填写完毕。

通过使用受控表单,React 组件能够更加灵活和可控地处理用户输入,提高了应用的可维护性和用户体验。

2.React中如何获取DOM

在 React 中获取 DOM 元素通常是通过 Refs(引用)来实现的。Refs 提供了一种直接访问在 render 方法中创建的 DOM 节点或 React 元素的方式。这种访问方式是为了避免直接操作 DOM,符合 React 的声明式和组件化的设计理念。

使用 Refs 获取 DOM

1. 创建 Refs

在函数式组件中,可以使用 useRef 钩子来创建 Ref 对象:

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

const MyComponent = () => {
  // 创建一个 Ref 对象
  const myRef = useRef(null);

  // 在 useEffect 中操作 Ref
  useEffect(() => {
    console.log(myRef.current);  // 输出 Ref 对象的当前值(关联的 DOM 节点)
  }, []);

  return (
    <div ref={myRef}>
      {/* 这里是组件内容 */}
    </div>
  );
};

export default MyComponent;
2. 访问 DOM 节点

通过 ref.current 属性可以访问到 Ref 对象关联的 DOM 节点。需要注意的是,Ref 对象在组件的整个生命周期中保持不变,但 ref.current 的值会随着组件的渲染和卸载而变化。

3. 类组件中的 Refs

在类组件中,Refs 的创建和访问稍有不同:

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

class MyComponent extends Component {
  constructor(props) {
    super(props);
    // 创建一个 Ref 对象
    this.myRef = React.createRef();
  }

  componentDidMount() {
    console.log(this.myRef.current);  // 输出 Ref 对象的当前值(关联的 DOM 节点)
  }

  render() {
    return (
      <div ref={this.myRef}>
        {/* 这里是组件内容 */}
      </div>
    );
  }
}

export default MyComponent;

在类组件中,通过 React.createRef() 方法创建 Ref 对象,并在 componentDidMount 生命周期中访问 this.myRef.current 获取 DOM 节点。

使用场景

  • 直接操作 DOM: 当需要在 React 中进行 DOM 操作时,例如测量元素尺寸、动画操作等,可以使用 Refs 来获取并操作 DOM 元素。
  • 集成第三方库: 当需要与不支持 React 的第三方库(如 D3.js、Chart.js 等)集成时,Refs 提供了一种访问和控制 DOM 的方式。
  • 焦点控制: 控制输入框、模态框等组件的焦点状态。

注意事项

  • 避免滥用 Refs: 在大多数情况下,应该优先考虑使用 React 的数据驱动和状态管理方式,而不是直接操作 DOM。
  • Refs 和函数式组件 : 在函数式组件中,确保使用 useRef 钩子来创建 Ref 对象,而不是直接操作 DOM。

通过使用 Refs,在 React 中可以安全地获取和操作 DOM 元素,同时保持 React 的组件化和声明式编程模型的优势。

3.组件间通信

在 React 中,组件间通信是非常常见和重要的一部分,特别是在大型应用程序中,不同组件之间需要相互传递数据、状态或触发特定行为。以下是几种主要的 React 组件间通信方式:

1. Props 属性传递

Props(属性)是 React 中组件间通信最基础和常见的方式。通过将数据或函数作为属性传递给子组件,可以实现父组件向子组件的数据传递。

父组件传递数据给子组件:

react 复制代码
// ParentComponent.jsx
import React from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
  const data = 'Hello from parent';

  return (
    <div>
      <ChildComponent message={data} />
    </div>
  );
};

export default ParentComponent;

子组件接收并使用 Props 数据:

react 复制代码
// ChildComponent.jsx
import React from 'react';

const ChildComponent = (props) => {
  return (
    <div>
      <p>{props.message}</p>
    </div>
  );
};

export default ChildComponent;

2. Callback 函数传递

通过将回调函数作为 Props 传递给子组件,子组件可以调用该函数并将数据或事件传递回父组件。

父组件定义回调函数并传递给子组件:

react 复制代码
// ParentComponent.jsx
import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
  const [message, setMessage] = useState('');

  const handleCallback = (data) => {
    setMessage(data);
  };

  return (
    <div>
      <p>Message from child: {message}</p>
      <ChildComponent callback={handleCallback} />
    </div>
  );
};

export default ParentComponent;

子组件调用回调函数并传递数据:

react 复制代码
// ChildComponent.jsx
import React from 'react';

const ChildComponent = (props) => {
  const sendDataToParent = () => {
    const data = 'Hello from child';
    props.callback(data);
  };

  return (
    <div>
      <button onClick={sendDataToParent}>Send Data</button>
    </div>
  );
};

export default ChildComponent;

3. Context API

Context API 提供了一种在组件树中传递数据的方法,避免了通过 Props 层层传递数据的繁琐过程。适合在多层级嵌套的组件中使用,允许跨越组件层级直接传递数据。

创建 Context 对象并提供数据:

react 复制代码
// MyContext.js
import React from 'react';

const MyContext = React.createContext();

export const MyProvider = MyContext.Provider;
export const MyConsumer = MyContext.Consumer;

使用 Context 提供数据并在子组件中消费:

react 复制代码
// ParentComponent.jsx
import React from 'react';
import { MyProvider } from './MyContext';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
  const data = 'Hello from context';

  return (
    <MyProvider value={data}>
      <ChildComponent />
    </MyProvider>
  );
};

export default ParentComponent;

在子组件中消费 Context 中的数据:

react 复制代码
// ChildComponent.jsx
import React, { useContext } from 'react';
import { MyContext } from './MyContext';

const ChildComponent = () => {
  const data = useContext(MyContext);

  return (
    <div>
      <p>{data}</p>
    </div>
  );
};

export default ChildComponent;

4. Redux 或其他状态管理工具

对于大型应用程序中复杂的状态管理需求,可以使用 Redux 或其他状态管理工具(如 MobX)来集中管理应用程序的状态,并通过全局状态来实现组件间通信。这种方式适合需要多个组件共享状态或频繁更新状态的场景。

选择合适的通信方式

  • Props 传递:简单、直观,适用于父子组件间的数据传递。
  • Callback 函数:父组件可以向子组件传递函数来处理子组件中的事件,适合于子组件向父组件传递数据或事件。
  • Context API:适用于跨组件层级传递数据,避免 Props 层层传递的麻烦。
  • Redux 或其他状态管理工具:适用于需要全局状态管理或复杂的状态更新和同步需求的应用程序。

根据具体的场景和需求,选择适合的组件间通信方式是提高 React 应用开发效率和可维护性的关键。

4.useEffect

useEffect 是 React Hooks 中非常重要的一个钩子函数,用于在函数组件中执行副作用操作。副作用操作通常包括订阅数据、手动操作 DOM 和执行数据获取等。

基本用法

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

const MyComponent = () => {
  // 定义一个状态来存储数据
  const [data, setData] = useState(null);

  // useEffect 第一个参数是一个函数,第二个参数是一个数组
  useEffect(() => {
    // 在组件加载后和每次更新后执行

    // 这里可以进行数据获取、订阅操作、手动 DOM 更新等异步操作
    fetchData();

    // 清理函数,可选,用于清理副作用
    return () => {
      cleanupFunction();
    };
  }, []); // 空数组意味着只在组件加载后执行一次

  const fetchData = async () => {
    // 异步操作示例,获取数据
    const result = await fetch('https://api.example.com/data');
    const data = await result.json();
    setData(data);
  };

  const cleanupFunction = () => {
    // 清理函数,比如清除订阅或取消定时器
    // 在组件卸载时执行
  };

  return (
    <div>
      {data ? (
        <p>Data loaded: {JSON.stringify(data)}</p>
      ) : (
        <p>Loading...</p>
      )}
    </div>
  );
};

export default MyComponent;

useEffect 的工作原理

  • 第一个参数(effect):一个函数,包含需要执行的副作用操作,可以是数据获取、订阅操作、DOM 操作等异步任务。
  • 第二个参数(dependencies 数组):可选参数,指定 effect 的依赖项。当依赖项发生变化时,effect 就会重新执行。如果不传递该参数,每次组件更新时都会执行 effect。

依赖项的作用

  • 空数组 [] :effect 仅在组件加载和卸载时执行,相当于 componentDidMountcomponentWillUnmount 生命周期的结合体。
  • 包含状态或属性的数组 :effect 会在依赖项中的状态或属性发生变化时执行。比如 [count] 会在 count 状态更新时执行 effect。
  • 不传递第二个参数 :effect 在每次组件更新时都会执行,相当于 componentDidUpdate 生命周期。

清理副作用

在 effect 函数中可以返回一个清理函数,用于清理副作用,比如取消订阅、清除定时器等。这样可以避免内存泄漏和无效的异步操作。

react 复制代码
useEffect(() => {
  const subscription = subscribeToData();
  
  return () => {
    subscription.unsubscribe(); // 清理订阅
  };
}, [dependency]);

总结

useEffect 是 React Hooks 提供的强大工具,用于处理函数组件中的副作用操作。通过指定依赖项数组,可以精确控制 effect 的执行时机,避免不必要的重复执行,提高组件性能和可维护性。

5.自定义Hook

自定义 Hook 是 React 中的一个强大功能,它允许你将组件逻辑提取到可复用的函数中。自定义 Hook 的命名通常以 use 开头。

创建一个自定义 Hook

我们将创建一个简单的自定义 Hook useCounter,它管理一个计数器的状态并提供增加和减少计数器的方法。

Step 1: 定义自定义 Hook
react 复制代码
import { useState } from 'react';

const useCounter = (initialValue = 0) => {
  const [count, setCount] = useState(initialValue);

  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);

  return { count, increment, decrement };
};

export default useCounter;
Step 2: 使用自定义 Hook

你可以在任意函数组件中使用这个自定义 Hook:

复制代码
import React from 'react';
import useCounter from './useCounter';

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
};

export default CounterComponent;

自定义 Hook 的优势

  1. 逻辑复用:将重复使用的逻辑提取到自定义 Hook 中,使代码更加模块化和可复用。
  2. 更清晰的组件结构:通过将复杂逻辑抽离到自定义 Hook 中,组件代码变得更简洁和易读。
  3. 状态隔离:每次调用自定义 Hook 都会生成独立的状态,互不影响。

复杂的自定义 Hook 示例

创建一个自定义 Hook useFetch 来处理数据获取:

Step 1: 定义 useFetch Hook
react 复制代码
import { useState, useEffect } from 'react';

const useFetch = (url) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        const data = await response.json();
        setData(data);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
};

export default useFetch;
Step 2: 使用 useFetch Hook
react 复制代码
import React from 'react';
import useFetch from './useFetch';

const DataComponent = () => {
  const { data, loading, error } = useFetch('https://api.example.com/data');

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
};

export default DataComponent;

总结

自定义 Hook 允许你将组件逻辑提取到可复用的函数中,提高代码的可读性和维护性。通过自定义 Hook,可以更方便地复用逻辑、管理复杂的状态和副作用,从而简化组件代码。

相关推荐
袁小皮皮不皮1 小时前
1.HCIP BFD 学习笔记(优化版)
服务器·网络·笔记·网络协议·学习·智能路由器·ip
装不满的克莱因瓶1 小时前
【自动驾驶领域】学习 Cityscapes 数据集——城市街景语义理解的标准基准
人工智能·pytorch·python·深度学习·学习·机器学习·自动驾驶
清辞8532 小时前
产品经理需求推进流程
大数据·深度学习·学习·产品经理
烬羽3 小时前
后端返回的 JSON 字符串,浏览器怎么"看懂"的?——Ajax 全链路拆解
javascript
YM52e3 小时前
鸿蒙PC ArkTS 声明合并问题深度解析与最佳实践
学习·华为·harmonyos·鸿蒙·鸿蒙系统
半个落月3 小时前
一个新手用 Bun + Axios 调通 DeepSeek API 的实践记录
javascript
不好听6133 小时前
深入理解链表:线性数据结构的另一面
javascript·数据结构
林希_Rachel_傻希希4 小时前
学React治好了我的焦虑症,1小时速通React 前20分钟。
前端·javascript·面试
小林ixn4 小时前
从 Ajax 到异步编程:JSON 序列化、Event Loop 与 XHR 请求完全解析
javascript
海兰4 小时前
【实用程序】电商销售分析仪表盘 — 从零搭建一个AI参与的全栈数据洞察系统
人工智能·学习·算法