【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 函数封装数据请求的逻辑。
  • 把评论中的每一项抽象成一个独立的组件实现渲染。
相关推荐
mldong8 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排8 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60619 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角10 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!10 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰10 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi12 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen12 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马13 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu13 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss