玩命加载中🤣🤣🤣

React-02-组件通信&useEffect


React-02-组件通信&useEffect

父子通信

父子通信-父传子

实现步骤:

  1. 父组件传递数据 - 在子组件标签上绑定属性
  2. 子组件接收数据 - 子组件通过 props 参数接收数据
// 2.子组件通过prop对象拿到父组件数据
function Son(prop) {
  return (
    <div style={{ background: "pink", width: "300px", height: "100px" }}>
      我是子组件, 父组件的数据如下
      {/* 3.通过prop属性拿到具体数据 */}
      <div> {prop.fData}</div>
    </div>
  );
}

function App() {
  const name = "父组件数据";
  return (
    <div className="App">
      {/* 1.父组件传递数据 */}
      <Son fData={name}></Son>
    </div>
  );
}

export default App;

props说明

function Son(prop) {
  // 打印所有 prop 对象
  console.log(prop)
  return (
    <div style={{ background: "pink", width: "300px", height: "100px" }}>
      我是子组件, 父组件的数据如下
      {/* 3.通过prop拿到具体属性 */}
      <div> {prop.name}</div>
      <div> {prop.age}</div>
      <div> {prop.hobby}</div>
    </div>
  );
}

function App() {
  const name = "张三";
  const age = 18;
  const hobby = ["跑步", "游泳"];
  const obj = {"obj": "对象"}
  const action = () => console.log("study");
  return (
    <div className="App">
      {/* 1.父组件传递数据 */}
      <Son name={name} age={age} hobby={hobby} obj={obj} action={action}></Son>
    </div>
  );
}

export default App;

控制台

{action: () => console.log("study")
age: 18
hobby: (2) ['跑步', '游泳']
name: "张三"
obj: {obj: '对象'}
[[Prototype]]: Object

特殊的prop-children

function Son(prop) {
  // 打印所有 prop 对象
  console.log(prop);
  return (
    <div style={{ background: "pink", width: "300px", height: "100px" }}>
      我是子组件, 父组件的数据如下
      <br />
      {/* 子组件可以从 prop.children 中去取 */}
      {prop.children}
    </div>
  );
}

function App() {
  return (
    <div className="App">
      <Son>
        {/* 特殊:如果父组件嵌套了一个组件传进来 */}
        <span>子组件</span>
      </Son>
    </div>
  );
}

export default App;

父子通信-子传父

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

子传父示例,并且实时渲染展示

  1. 在父组件中定义一个接收数据的函数
  2. 将函数传递到子组件,这里prop名有规范(以on开头)
  3. 子组件在 prop 中拿到父组件函数
  4. 子组件通过回调函数将数据发送给父组件
  5. 父组件可以通过 useState 绑定子组件发送的消息,并且加以渲染
import { useState } from "react";

// 3. 子组件在 prop 中拿到父组件函数
function Son({onGetMsg}) {
  const msg = "我发送了一条消息";
  return (
    <div style={{ background: "pink", width: "300px", height: "100px" }}>
      我是子组件<br/>
      {/* 4. 子组件通过回调函数将数据发送给父组件 */}
      <button onClick={() => onGetMsg(msg)}>发送消息给父组件</button>
    </div>
  );
}

function App() {
  // 5. 父组件可以通过 useState 绑定子组件发送的消息,并且加以渲染
  const [childMsg, setChildMsg] = useState('')
  // 1.在父组件中定义一个接收数据的函数
  const getMsg = (msg) => {
    console.log(msg)
    setChildMsg(msg)
  }
  return (
    <div className="App">
      {childMsg}
      {/* 2. 将函数传递到子组件,这里prop名有规范(以on开头) */}
      <Son onGetMsg={getMsg}></Son>
    </div>
  );
}

export default App;

父子通信-兄弟组件通信

实现思路: 借助 状态提升 机制,通过共同的父组件进行兄弟之间的数据传递

  1. A组件先通过子传父的方式把数据传递给父组件App
  2. App拿到数据之后通过父传子的方式再传递给B组件
import { useState } from "react";

// B组件拿到数据并且使用
function ChildB({ msg }) {
  return (
    <div style={{ background: "yellow", width: "300px" }}>
      B: 我拿到了 {msg}
    </div>
  );
}

function ChildA({ onGetMsg }) {
  const msg = "我是A";
  // 3. 在A组件中调用回调函数,并且将数据传递给父组件
  return (
    <div style={{ background: "pink", width: "300px" }}>
      <button onClick={() => onGetMsg(msg)}>B</button>
    </div>
  );
}

// App -> index.js -> public/index.html(root)
function App() {
  // 3. 定义B组件的State
  const [aMsg, setAMsg] = useState("");
  // 1. 定义A组件的回调函数
  const getMsg = (msg) => {
    console.log(msg);
    setAMsg(msg);
  };
  return (
    <div className="App">
      {/* 2. 将回调函数传递给子A组件 */}
      <ChildA onGetMsg={getMsg}></ChildA>
      {/* 4. 将State传递给B组件 */}
      <ChildB msg={aMsg}></ChildB>
    </div>
  );
}

export default App;

React副作用管理-useEffect

概念

useEffect 是一个 React Hook 函数,用于在 React 组件中创建不是由事件引起而是由渲染本身引起的操作(副作用), 比 如发送 AJAX 请求,更改 DOM 等等

image-20260111195140637

useEffect 副作用函数的执行时机存在多种情况,根据传入依赖项的不同,会有不同的执行表现

依赖项 副作用功函数的执行时机
没有依赖项 组件初始渲染 + 组件更新时执行
空数组依赖 只在初始渲染时执行一次
添加特定依赖项 组件初始渲染 + 依赖项变化时执行

代码示例

import { useEffect, useState } from "react";

function App() {
  const [count, setCount] = useState(0);
  // 当组件加载完成后会调用 useEffect
  useEffect(() => {
    async function getMsg() {
      console.log("我执行了")
    }
    getMsg();
  // }); // 1. 组件每次更新都会执行一次
  // }, []); // 2. 只会在首次渲染执行一次
  }, [count]); // 3. 在指定数据发生变化时执行
  const click = () => console.log("我执行了");
  const [msg, setMsg] = useState("");
  return (
    <div className="App">
      <button onClick={() => setCount(count + 1)}>{count}</button>
    </div>
  );
}

export default App;

清除副作用

概念:在useEffect中编写的由渲染本身引起的对接组件外部的操作,社区也经常把它叫做副作用操作,比如在useEffect中开启了一个定时器,我们想在组件卸载时把这个定时器再清理掉,这个过程就是清理副作用

通过条件渲染模拟组件卸载

import { useEffect, useState } from "react";

function Child() {
  useEffect(() => {
    const timer = setInterval(() => {
      console.log("定时器执行中");
    }, 1000);
    return () => {
      // 清除副作用(组件卸载时)
      clearInterval(timer)
    }
  });

  return <button>我是子组件</button>;
}

function App() {
  const [show, setShow] = useState(true);
  return (
    <div className="App">
      <button onClick={() => setShow(!show)}>点我 装载/卸载</button>
      {show && <Child />}
    </div>
  );
}

export default App;

自定义Hook

基于上一个demo,可以发现定时器的装卸在是靠如下的逻辑来实现

const [show, setShow] = useState(true);
  return (
    <div className="App">
      <button onClick={() => setShow(!show)}>点我 装载/卸载</button>
      {show && <Child />}
    </div>
  );

下面可以通过组件封装进行优化:

  1. 声明一个以use打头的函数
  2. 在函数体内封装可复用的逻辑(只要是可复用的逻辑)
  3. 把组件中用到的状态或者回调return出去(以对象或者数组)
  4. 在哪个组件中要用到这个逻辑,就执行这个函数,结构出来状态和回调进行使用
import { useEffect, useState } from "react";

function useToggle() {
  // 可复用的逻辑代码
  const [value, setValue] = useState(true);
  const toggle = () => setValue(!value)
  return {value, toggle}
}

function App() {
  const {value, toggle} = useToggle()
   return (
    <div className="App">
      <button onClick={toggle}>点我装/卸载</button>
      {value && <div>我是一个标签</div>}
    </div>
  );
}

export default App;

文章作者: 👑Dee👑
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 👑Dee👑 !
  目录