【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 函数封装数据请求的逻辑。
  • 把评论中的每一项抽象成一个独立的组件实现渲染。
相关推荐
还是大剑师兰特24 分钟前
D3的竞品有哪些,D3的优势,D3和echarts的对比
前端·javascript·echarts
王解24 分钟前
【深度解析】CSS工程化全攻略(1)
前端·css
一只小白菜~30 分钟前
web浏览器环境下使用window.open()打开PDF文件不是预览,而是下载文件?
前端·javascript·pdf·windowopen预览pdf
方才coding35 分钟前
1小时构建Vue3知识体系之vue的生命周期函数
前端·javascript·vue.js
阿征学IT39 分钟前
vue过滤器初步使用
前端·javascript·vue.js
王哲晓40 分钟前
第四十五章 Vue之Vuex模块化创建(module)
前端·javascript·vue.js
丶213640 分钟前
【WEB】深入理解 CORS(跨域资源共享):原理、配置与常见问题
前端·架构·web
发现你走远了40 分钟前
『VUE』25. 组件事件与v-model(详细图文注释)
前端·javascript·vue.js
Mr.咕咕43 分钟前
Django 搭建数据管理web——商品管理
前端·python·django
张张打怪兽1 小时前
css-50 Projects in 50 Days(3)
前端·css