【React】入门Day02 —— 表单控制、组件通信、副作用管理与自定义 Hook

本文主要介绍了 React 的相关知识,包括表单控制、组件通信、副作用管理、自定义 Hook 以及 Hooks 使用规则等内容,并通过一些案例进行了说明,以下是详细总结:

1. React 表单控制

  • 受控绑定

    javascript 复制代码
    import React, { useState } from 'react';
    
    function App() {
      const [value, setValue] = useState('');
      return (
        <input 
          type="text" 
          value={value} 
          onChange={e => setValue(e.target.value)}
        />
      );
    }
    • 概念:使用 React 组件的状态(useState)控制表单的状态。
    • 示例代码 :通过useState定义表单值状态,在input组件上绑定valueonChange事件,实现表单值与状态的同步。
  • 非受控绑定

    javascript 复制代码
    import React, { useRef } from 'react';
    
    function App() {
      const inputRef = useRef(null);
      const onChange = () => {
        console.log(inputRef.current.value);
      };
    
      return (
        <input 
          type="text" 
          ref={inputRef}
          onChange={onChange}
        />
      );
    }
    • 概念:通过获取 DOM 的方式获取表单的输入数据。
    • 示例代码 :使用useRef创建引用,在input组件上绑定refonChange事件,通过引用获取表单值。

2. 案例 - B 站评论案例

  • 实现手机输入框评论内容并发布评论,涉及 id 处理(如使用uuid)和时间处理(如使用day.js)。
javascript 复制代码
import React, { useState } from 'react';
import uuid from 'uuid';
import dayjs from 'dayjs';

function CommentComponent() {
  const [comment, setComment] = useState('');
  const handleSubmit = () => {
    const commentId = uuid.v4();
    const commentTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
    // 这里可以添加发送评论的逻辑,比如调用接口
    console.log(`评论内容:${comment},评论ID:${commentId},评论时间:${commentTime}`);
  };

  return (
    <div>
      <input 
        type="text" 
        value={comment} 
        onChange={e => setComment(e.target.value)}
      />
      <button onClick={handleSubmit}>发布评论</button>
    </div>
  );
}

3. React 组件通信

  • 概念:组件之间的数据传递,根据组件嵌套关系不同有不同通信手段。

  • 父子通信 - 父传子

    • 基础实现

      • 实现步骤 :父组件在子组件标签上绑定属性传递数据,子组件通过props接收数据。

      • 示例代码 :展示了父组件传递name属性给子组件,子组件接收并渲染的代码。

        javascript 复制代码
        function Son(props) {
          return <div>{props.name}</div>;
        }
        
        function App() {
          const name = 'this is app name';
          return (
            <div>
               <Son name={name}/>
            </div>
          );
        }
    • props 说明

      • 可以传递任意合法数据,如数字、字符串等多种类型。
      • props是只读对象,子组件只能读取不能直接修改,父组件数据由父组件修改。
    • 特殊的 prop - children :当内容嵌套在组件标签内部时,组件会在children属性中接收该内容。

  • 父子通信 - 子传父

    • 核心思路:子组件调用父组件传递的函数并传递参数。

    • 示例代码 :子组件通过按钮点击事件调用父组件传递的函数,将数据传递给父组件。

      javascript 复制代码
      function Son({ onGetMsg }) {
        const sonMsg = 'this is son msg';
        return (
          <div>
            {/* 在子组件中执行父组件传递过来的函数 */}
            <button onClick={() => onGetMsg(sonMsg)}>send</button>
          </div>
        );
      }
      
      function App() {
        const getMsg = (msg) => console.log(msg);
      
        return (
          <div>
            {/* 传递父组件中的函数到子组件 */}
             <Son onGetMsg={getMsg}/>
          </div>
        );
      }
  • 兄弟组件通信

    • 实现思路:借助 "状态提升" 机制,通过共同的父组件进行数据传递,即 A 组件先子传父给父组件 App,App 再父传子给 B 组件。

    • 示例代码 :展示了 A 组件传递数据给 App,App 再传递给 B 组件的完整代码。

      javascript 复制代码
      import { useState } from "react";
      
      function A({ onGetAName }) {
        // Son组件中的数据
        const name = 'this is A name';
        return (
          <div>
            this is A compnent,
            <button onClick={() => onGetAName(name)}>send</button>
          </div>
        );
      }
      
      function B({ name }) {
        return (
          <div>
            this is B compnent,
            {name}
          </div>
        );
      }
      
      function App() {
        const [name, setName] = useState('');
        const getAName = (name) => {
          setName(name);
        };
        return (
          <div>
            this is App
            <A onGetAName={getAName} />
            <B name={name} />
          </div>
        );
      }
      export default App;
  • 跨层组件通信

    • 实现步骤

      • 使用createContext创建上下文对象Ctx
      • 顶层组件(App)通过Ctx.Provider提供数据。
      • 底层组件(B)通过useContext获取数据。
    • 示例代码 :展示了从 App 到 A 再到 B 组件的跨层通信代码。

      javascript 复制代码
      import { createContext, useContext } from "react";
      
      // 1. createContext方法创建一个上下文对象
      const MsgContext = createContext();
      
      function A() {
        return (
          <div>
            this is A component
            <B />
          </div>
        );
      }
      
      function B() {
        // 3. 在底层组件 通过useContext钩子函数使用数据
        const msg = useContext(MsgContext);
        return (
          <div>
            this is B compnent,{msg}
          </div>
        );
      }
      
      function App() {
        const msg = 'this is app msg';
        return (
          <div>
            {/* 2. 在顶层组件 通过Provider组件提供数据 */}
            <MsgContext.Provider value={msg}>
              this is App
              <A />
            </MsgContext.Provider>
          </div>
        );
      }
      export default App;

4. React 副作用管理 - useEffect

  • 概念理解 :用于在 React 组件中创建由渲染本身引起的操作(副作用),如发送 AJAX 请求、更改 DOM 等。

    javascript 复制代码
    import React, { useEffect, useState } from 'react';
    
    function App() {
      const [data, setData] = useState(null);
    
      useEffect(() => {
        // 这里可以模拟发送请求获取数据
        const mockData = { message: '模拟数据' };
        setData(mockData);
      }, []);
    
      return (
        <div>
          {data && <div>{data.message}</div>}
        </div>
      );
    }

    基础使用

    • 需求示例 :在组件渲染完毕后从服务端获取频道列表数据并显示。

      javascript 复制代码
      import React, { useEffect, useState } from 'react';
      
      function App() {
        const [data, setData] = useState(null);
      
        useEffect(() => {
          fetch('https://example.com/api/data')
          .then(response => response.json())
          .then(data => setData(data));
        }, []);
      
        return (
          <div>
            {data && <div>{data.message}</div>}
          </div>
        );
      }
    • 参数说明

      • 参数 1 是副作用函数,内部放置要执行的操作。
      • 参数 2 是可选的数组(依赖项),影响副作用函数的执行时机,空数组时只在初始渲染后执行一次。
  • useEffect 依赖说明

    • 无依赖项时,组件初始渲染和更新时执行副作用函数。
    • 空数组依赖时,只在初始渲染时执行一次。
    • 添加特定依赖项时,组件初始渲染和依赖项变化时执行。
  • 清除副作用

    • 概念 :清理在useEffect中编写的对接组件外部的操作,如组件卸载时清理定时器。

    • 示例代码 :展示了在useEffect中开启定时器,并在组件卸载时清理定时器的代码。

      javascript 复制代码
      import React, { useEffect, useState } from 'react';
      
      function Son() {
        // 1. 渲染时开启一个定时器
        useEffect(() => {
          const timer = setInterval(() => {
            console.log('定时器执行中...');
          }, 1000);
          return () => {
            // 清除副作用(组件卸载时)
            clearInterval(timer);
          }
        }, []);
        return <div>this is son</div>;
      }
      
      function App() {
        // 通过条件渲染模拟组件卸载
        const [show, setShow] = useState(true);
        return (
          <div>
            {show && <Son />}
            <button onClick={() => setShow(false)}>卸载Son组件</button>
          </div>
        );
      }
      export default App;

5. 自定义 Hook 实现

  • 概念 :以use打头的函数,用于实现逻辑的封装和复用。

  • 示例代码 :展示了一个自定义useToggle函数,封装了布尔值切换的逻辑,并在其他组件中使用的代码,同时介绍了自定义 hook 的通用封装思路。

    javascript 复制代码
    import { useState } from 'react';
    
    function useToggle() {
      // 可复用的逻辑代码
      const [value, setValue] = useState(true);
      const toggle = () => setValue(!value);
      // 哪些状态和回调函数需要在其他组件中使用 return
      return {
        value,
        toggle
      };
    }
    
    function App() {
      const { value, toggle } = useToggle();
      return (
        <div>
          {value && <div>this is div</div>}
          <button onClick={toggle}>toggle</button>
        </div>
      );
    }

6. React Hooks 使用规则

  • 只能在组件中或其他自定义 Hook 函数中调用。
  • 只能在组件的顶层调用,不能嵌套在iffor或其他函数中。

7. 案例 - 优化 B 站评论案例

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

// 自定义Hook函数封装数据请求逻辑
function useFetchComments() {
  const [comments, setComments] = useState([]);
  useEffect(() => {
    fetch('https://example.com/api/comments')
    .then(response => response.json())
    .then(data => setComments(data));
  }, []);
  return comments;
}

function CommentItem({ comment }) {
  return <div>{comment.text}</div>;
}

function CommentList() {
  const comments = useFetchComments();
  return (
    <div>
      {comments.map(comment => (
        <CommentItem key={comment.id} comment={comment} />
      ))}
    </div>
  );
}

function App() {
  return (
    <div>
      <CommentList />
    </div>
  );
}
  • 使用请求接口的方式获取评论列表并渲染。
  • 使用自定义 Hook 函数封装数据请求的逻辑。
  • 把评论中的每一项抽象成一个独立的组件实现渲染。
相关推荐
崔庆才丨静觅12 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606112 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了12 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅13 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅13 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅13 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment13 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅14 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊14 小时前
jwt介绍
前端
爱敲代码的小鱼14 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax