使用 React Hooks 将数据从子组件传递到父组件
最近我接到一个挑战,要用 Hooks 实现一个简单的 React 身份验证系统。有人给我推荐了这篇文章作为示例,我发现用一行代码控制整个应用的身份验证是一个很有意思的方法。在这个演示中,我希望用户能够输入用户名来“登录”,然后网站会显示“hello, [username]”来欢迎用户。
总体布局
这个演示背后的基本思路是在根父组件中设置一个单一状态,用于保存用户身份验证信息。根据用户是否通过身份验证,加载不同版本的网站。
const App = () => {
const [user, setUser] = useState(null);
return user ? <AuthWebsite/> : <NoAuthWebsite/>
};
很简单,对吧?但是状态如何更新呢?必须有一种方法将用户信息传递到组件树的上层,以便更新存储在[用户]状态中的信息。
从子级向父级传递数据
等等,单向数据流不是 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>
);
};
(这里的状态仅用于在表单中存储用户响应)
上面,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)} />
);
};
现在,我们已经将用户提交的用户名设置为 [user] 状态。如果该状态存在,我们将加载网站的授权版本。如果您注意到,我们将一个注销函数传递给了 AuthWebsite 组件,以便用户可以注销,网站可以返回到其默认(未授权)状态。不过,在这种情况下,我们不需要将子组件传递到组件树中,因为只需将 User 设置为 null 即可。我们现在可以构建授权网站组件,并使其能够使用用户名来欢迎用户:
const AuthWebsite = ({ logout, user }) => {
return (
<div>
<h2>Hello, {user}</h2>
<div className="logout_button" onClick={() => logout()}>
logout
</div>
</div>
);
};
就这样!一个简单的 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>
)
}
.overlay_shown {
opacity: 1;
}
.overlay_hidden {
display: none;
opacity: 0;
}
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>
)
}
就这样!把它们连接在一起,并添加一些可视化显示来查看数据流路径后,您可以在这里查看完整的现场演示,或者在这里查看源代码。
结论
使用函数是将数据向上传递到组件树的绝佳方式。它可以用于多种用途,最显著的是基于用户在子组件中的交互/输入进行渲染。将此技巧与 React Hooks 结合使用,有助于编写美观且易于维护的代码,因为通过函数式组件和函数本身,逻辑流程更容易理解。
如果您有任何问题、意见、问题,或者只是想聊天,请随时给我留言。
文章来源:https://dev.to/pnkfluffy/passing-data-from-child-to-parent-with-react-hooks-1ji3