React 中的 prop 钻孔是什么?

2025-06-04

React 中的 prop 钻孔是什么?

呦吼,我的朋友们!!!

Prop 钻取是指在组件层次结构的多个层级之间向下传递数据或状态的过程。顺便提一下,它指的是将数据从父组件传递到其子组件,再从子组件传递到其子组件,以此类推,直到数据到达需要它的组件。

Prop 钻取是管理应用程序状态的必要且有效的方法,但当组件层次结构变得过深或复杂时,它也可能成为一个问题。这会导致一些问题,例如代码重复、认知负担增加以及可维护性下降。

在本文中,我们将讨论什么是 props、什么是 prop 钻探以及它如何影响您的应用程序。我们还将探讨一些在代码库中修复 prop 钻探的最佳实践。

地平线的怀抱,迎风而立,阳光洒满脸庞。让我们扬帆起航,驶向螺旋桨钻探的深处。


React 中的 Props 是什么?

Props(又称“属性”)是组件的输入。它们是单个值或包含一组值的对象,这些值在创建时会传递给组件,类似于 HTML 标签的属性。在这里,数据从父组件向下传递到子组件。

Props 是只读的,这意味着它们不能被组件本身修改。它们用于自定义组件的行为或外观,并以单向流的方式在组件树中向下传递。

向你展示我的意思......

function Snake(props) {
  return <h1>Hello, {props.name}!</h1>;
}

function DeadliestSnakes() {
  return (
    <div>
      <Snake name="Inland Taipan" />
      <Snake name="King Cobra" />
      <Snake name="Russell's Viper" />
      <Snake name="Black Mamba" />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

让我们了解一下支柱钻孔

支柱钻井

Prop 钻取是指父组件将数据向下传递给其子组件,然后子组件又将相同的数据向下传递给它们自己的子组件。这个过程可以无限期地持续下去。最终,它会形成一长串的组件依赖关系,难以管理和维护。

假设你有一个组件用于显示博客文章列表。每篇博客文章都有标题、日期、作者和内容。为了显示这些信息,父组件需要将所有这些数据传递给其子组件,而这些子组件又需要将这些数据传递给它们自己的子组件,以此类推。

React DEV

您可以想象,这个过程会变得相当复杂和难以处理,特别是当您的应用程序的规模和复杂性不断增长时。


支柱钻井的问题

Prop 钻探可能会导致代码库中出现多个问题,让我们将其暴露出来:

代码重复

当数据需要通过多层组件向下传递时,可能会导致代码重复。这种情况发生在将相同的数据传递给多个子组件时,即使它们可能不需要所有数据。

这会导致代码臃肿和冗余,难以维护和调试。

增加认知负荷

Prop 钻取还会增加需要理解和浏览组件层次结构的开发人员的认知负担。随着组件和层级数量的增加,跟踪哪些组件传递了哪些数据以及这些数据在何处使用会变得越来越困难。

这会使识别和修复错误以及对代码库进行更改或更新变得更加困难。

可维护性降低

随着时间的推移,Prop 钻取会导致可维护性下降。随着应用程序规模和复杂度的增长,添加新功能或更改现有功能都会变得更加困难。

最终,代码库变得难以使用,这会导致生产力下降和开发人员的挫败感增加。


寻找更干净的 React 代码

有几种方法可以修复代码库中的 prop 钻孔问题。让我们来看一下:

使用状态管理库

解决 prop 钻取问题最有效的方法之一是使用状态管理库,例如ReduxMobX。这些库提供了一个集中式存储来管理应用程序状态,这有助于消除 prop 钻取的需要。

您无需通过多层组件传递数据,只需将每个组件连接到存储,然后直接访问所需的数据即可。

使用状态管理库

您可以重构代码以使用 Redux:

  • 定义一个保存蛇列表的 Redux 存储:
import { createStore } from "redux";

const initialState = {
  snakes: [],
};

function rootReducer(state = initialState, action) {
  switch (action.type) {
    case "ADD_SNAKE":
      return {
        ...state,
        snakes: [...state.snakes, action.payload],
      };

    case "DELETE_SNAKE":
      return {
        ...state,
        snakes: state.snakes.filter((snake) => snake.id !== action.payload.id),
      };

    case "TRACK_SNAKE":
      return {
        ...state,
        snakes: state.snakes.map((snake) => {
          if (snake.id === action.payload.id) {
            return { ...snake, tracked: true };
          } else {
            return snake;
          }
        }),
      };
    default:
      return state;
  }
}

const store = createStore(rootReducer);
Enter fullscreen mode Exit fullscreen mode
  • 使用以下函数将您的组件连接到 Redux 存储connect()
import { connect } from "react-redux";

function SnakeList(props) {
  const { snakes } = props;

  return (
    <ul>
      {snakes.map((snake) => (
        <Snake key={snake.id} snake={snake} />
      ))}
    </ul>
  );
}

function mapStateToProps(state) {
  return {
    snakes: state.snakes,
  };
}

export default connect(mapStateToProps)(SnakeList);
Enter fullscreen mode Exit fullscreen mode
  • 调度 Redux 操作来添加、删除或跟踪蛇:
function Snake({ snake, deleteSnake, trackSnake }) {

  const onTrackSnake = (id) => () => {
    trackSnake(id);
  };

  const onDeleteSnake = (id) => () => {
    deleteSnake(id);
  };

  return (
    <li>
      <input
        type="checkbox"
        checked={snake.tracked}
        onChange={onTrackSnake(snake.id)}
      />
      {snake.title} ({snake.tracked ? "Tracked" : "Not Tracked"})
      <button onClick={onDeleteSnake(snake.id)}>Delete</button>
    </li>
  );
}

function mapDispatchToProps(dispatch) {
  return {
    deleteSnake: (id) => dispatch({ type: "DELETE_SNAKE", payload: { id } }),
    trackSnake: (id) => dispatch({ type: "TRACK_SNAKE", payload: { id } }),
  };
}

export default connect(null, mapDispatchToProps)(Snake);
Enter fullscreen mode Exit fullscreen mode

实现 Context API

如果你不想使用功能齐全的状态管理库,也可以考虑使用React 中的Context API。此 API 提供了一种在组件之间共享数据的方法,而无需进行 prop 钻取。

使用 Context API,您可以创建一个上下文对象来保存需要共享的数据。然后,您可以将此上下文对象传递给需要它的子组件,而无需通过...

实现 Context API

您可以使用 Context API 在组件之间共享蛇对象:

  • 创建蛇上下文对象:
import { createContext } from 'react';

export const SnakeContext = createContext({
  name: "Black Mamba",
  fangs: "6.5 mm",
  speed: "12.5 miles per hour",
  color: "#964B00", // dark brown
});
Enter fullscreen mode Exit fullscreen mode
  • 将您的组件包装在提供蛇上下文的提供程序组件中:
function Jungle(props) {
  const snake = {
    name: "Black Mamba",
    fangs: "6.5 mm",
    speed: "12.5 miles per hour",
    color: "#964B00", // dark brown
  };

  return (
    <SnakeContext.Provider value={snake}>
      <Header />
      <Main />
    </SnakeContext.Provider>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • 使用useContext()钩子访问子组件中的蛇对象:
import { useContext } from "react";

function Header() {
  const { color } = useContext(SnakeContext);

  return (
    <header style={{ backgroundColor: color }}>
      <h1>Snake</h1>
    </header>
  );
}

function Main() {
  const { name, fangs, speed } = useContext(SnakeContext);

  return (
    <main>
      <p>
        Name: <span>{name}</span>
      </p>
      <p>
        Venom Fangs: <span>{fangs}</span>
      </p>
      <p>
        Speed: <span>{speed}</span>
      </p>
    </main>
  );
}
Enter fullscreen mode Exit fullscreen mode

Context 并不局限于静态值。如果你在下次渲染时传递了不同的值,React 会更新所有读取该值的组件!这就是为什么 context 经常与 state 结合使用的原因。

上下文用例:

  1. 主题
  2. 经常账户
  3. 管理状态

如果树的不同部分的远距离组件需要某些信息,这很好地表明上下文将为您提供帮助。


在 React 开发的汪洋大海中,prop 钻探可能是一个难以驾驭的风暴挑战。但是,我的船长们,不要害怕!借助正确的工具和技术,您可以扬起简洁高效的代码之帆,让您的 React 应用程序驶向更平静的水域⛵️🌊

祝你编码愉快,React 之旅一帆风顺!!!🚀🌟🌈🏴‍☠️


❤ 动机:

蓝色有机世界海洋日.png


🍀支持

请考虑关注并支持我们,订阅我们的频道。非常感谢您的支持,这将帮助我们继续创作您喜爱的内容。提前感谢您的支持!

YouTube
Discord
GitHub

杜尔·达塞尔 #8740

文章来源:https://dev.to/codeofrelevancy/what-is-prop-drilling-in-react-3kol
PREV
2.5 年经验总结的 6 个 VueJs 基本技巧 #1
NEXT
使用 Vite.js + React.js、TypeScript 和 Tailwind CSS 构建利润率计算器