React基础学习-Day02

avatar
作者
猴君
阅读量:2

React基础学习-Day02

1.受控表单绑定

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

如何创建受控表单

1. 输入框(Input)

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

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)

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

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> 元素,需要注意选项列表的处理和初始选中值:

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 对象:

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 的创建和访问稍有不同:

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 中组件间通信最基础和常见的方式。通过将数据或函数作为属性传递给子组件,可以实现父组件向子组件的数据传递。

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

// 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 数据:

// ChildComponent.jsx import React from 'react';  const ChildComponent = (props) => {   return (     <div>       <p>{props.message}</p>     </div>   ); };  export default ChildComponent; 

2. Callback 函数传递

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

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

// 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; 

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

// 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 对象并提供数据:

// MyContext.js import React from 'react';  const MyContext = React.createContext();  export const MyProvider = MyContext.Provider; export const MyConsumer = MyContext.Consumer; 

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

// 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 中的数据:

// 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 和执行数据获取等。

基本用法

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

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

总结

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

5.自定义Hook

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

创建一个自定义 Hook

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

Step 1: 定义自定义 Hook
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
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
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,可以更方便地复用逻辑、管理复杂的状态和副作用,从而简化组件代码。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!