发布于 2025-12-10 1 阅读
0

使用 React Hooks 将数据从子组件传递到父组件

使用 React Hooks 将数据从子组件传递到父组件

最近我接到一个挑战,要用 Hooks 实现一个简单的 React 身份验证系统。有人给我推荐了这篇文章作为示例,我发现用一行代码控制整个应用的身份验证是一个很有意思的方法。在这个演示中,我希望用户能够输入用户名来“登录”,然后网站会显示“hello, [username]”来欢迎用户。

总体布局

这个演示背后的基本思路是在根父组件中设置一个单一状态,用于保存用户身份验证信息。根据用户是否通过身份验证,加载不同版本的网站。

const App = () => {
  const [user, setUser] = useState(null);

  return user ? <AuthWebsite/> : <NoAuthWebsite/>
};
Enter fullscreen mode Exit fullscreen mode

很简单,对吧?但是状态如何更新呢?必须有一种方法将用户信息传递到组件树的上层,以便更新存储在[用户]状态中的信息。

从子级向父级传递数据

等等,单向数据流不是 React 的核心设计理念吗?没错。而且我们不应该使用最常用的数据传递方法——props——将任何东西传递到组件树的上层。然而,我们实际上可以在父组件中设计函数,并将它们传递到下层组件树。我们可以将变量或任何其他数据作为参数传递到子组件中的函数中。

将用户名传递回组件树的子组件如下所示:

const NoAuthWebsite = ({ login }) => {
  const [userName, setUserName] = useState("");

  return (
    <form onSubmit={() => login(userName)}>
      <input
        placeholder="username"
        required="required"
        onChange={e => setUserName(e.target.value)}
        value={userName}
      />
      <button type="submit">
        submit
      </button>
    </form>
  );
};
Enter fullscreen mode Exit fullscreen mode

(这里的状态仅用于在表单中存储用户响应)

上面,login 被当作 NoAuthWebsite 组件的一个 prop。当用户加载网站时,该组件会向用户展示一个表单,要求用户填写用户名。用户名会被作为参数提交给 login 函数,并作为 prop 传递下去。现在,让我们在上面编写的父组件中添加 login() 函数,并将其传递下去:

const App = () => {
  const [user, setUser] = useState(null);

  return user ? (
    <AuthWebsite logout={() => setUser(null)} user={user} />
  ) : (
    <NoAuthWebsite login={username => setUser(username)} />
  );
};
Enter fullscreen mode Exit fullscreen mode

现在,我们已经将用户提交的用户名设置为 [user] 状态。如果该状态存在,我们将加载网站的授权版本。如果您注意到,我们将一个注销函数传递给了 AuthWebsite 组件,以便用户可以注销,网站可以返回到其默认(未授权)状态。不过,在这种情况下,我们不需要将子组件传递到组件树中,因为只需将 User 设置为 null 即可。我们现在可以构建授权网站组件,并使其能够使用用户名来欢迎用户:

const AuthWebsite = ({ logout, user }) => {
  return (
    <div>
      <h2>Hello, {user}</h2>
      <div className="logout_button" onClick={() => logout()}>
        logout
      </div>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

就这样!一个简单的 Web 应用身份验证演示,通过函数将数据从子组件传递到父组件!

向我们的应用程序添加一个更有趣的例子

迎接用户的登录表单有点枯燥。让我们重新运用这些概念,让它更有趣一些,做一个Modal (模态框),或者一个弹出式的覆盖卡片,用户可以选择提交或点击退出。这些模态窗口在网络上随处可见,几乎可以用于任何用途。

实现此效果非常简单,只需使用三元组来切换 CSS 即可。使用 CSS,您可以使用“display”属性控制 HTML 元素是否显示。与第一个示例中的操作类似,二进制状态可以控制组件的 className。然后,可以将切换状态的函数传递给覆盖组件本身。

const NoAuthWebsite = () => {
  const [overlay, setOverlay] = useState(false);

  return (
    <div className="flex_column">
      <div className={overlay ? "overlay_shown" : "overlay_hidden"}>
        <LoginOverlay
          removeOverlay={() => setOverlay(false)}
        />
      </div>
      <h2>You are not Authorized</h2>
      <div className="login_button" onClick={() => setOverlay(true)}>
        Login
      </div>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode
.overlay_shown {
  opacity: 1;
}

.overlay_hidden {
  display: none;
  opacity: 0;
}
Enter fullscreen mode Exit fullscreen mode

stopPropagation() 用于阻止 overlay_background div 上的 onClick 函数传播到其所有子级。如果没有它,点击模态框的任意位置都会导致 onClick 函数触发,并移除模态框。

const stopProp = e => {
  e.stopPropagation()
}

const LoginOverlay = ({ removeOverlay }) => {
  const [userName, setUserName] = useState("")

  return (
    <div className="overlay_background" onClick={e => removeOverlay()}>
      <div className="overlay_card" onClick={()) => stopProp(e)}>
        <form onSubmit={e => removeOverlay()}>
          <input
            placeholder="username"
            required="required"
            onChange={e => setUserName(e.target.value)}
            value={userName}
          />
          <button className="form_submit" type="submit">
            submit
          </button>
        </form>
      </div>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

就这样!把它们连接在一起,并添加一些可视化显示来查看数据流路径后,您可以在这里查看完整的现场演示,或者在这里查看源代码

结论

使用函数是将数据向上传递到组件树的绝佳方式。它可以用于多种用途,最显著的是基于用户在子组件中的交互/输入进行渲染。将此技巧与 React Hooks 结合使用,有助于编写美观且易于维护的代码,因为通过函数式组件和函数本身,逻辑流程更容易理解。

如果您有任何问题、意见、问题,或者只是想聊天,请随时给我留言。

文章来源:https://dev.to/pnkfluffy/passing-data-from-child-to-parent-with-react-hooks-1ji3