React自定义Hook跨组件共享状态是否需搭配useContext
问题背景
你当前共有4个相关React文件,实现需求为:在Login组件的用户名输入框更新输入值时,通过自定义useUser Hook设置username与showProfile状态,控制Profile组件显隐,同时在其他组件中读取username值展示。现有代码如下:
1. 自定义Hook useUser.js
import React, { useState } from "react"; const useUser = () => { const [username, setUsername] = useState(); const [showProfile, setShowProfile] = useState(); return { username, setUsername, showProfile, setShowProfile }; }; export default useUser;
2. 登录组件 Login.js
import React from "react"; import useUser from "../customHooks/useUser"; const Login = () => { const { setUsername, setShowProfile } = useUser(); return ( <div> <div> <input type="text" className="m-2 p-2" placeholder="Enter your email here" onChange={(e) => { setUsername(e.target.value); }} /> </div> <div> <input type="text" className="m-2 p-2" placeholder="Enter your password here" onChange={(e) => {}} /> </div> <div> <button className="m-2 p-2" onClick={() => { setShowProfile(true); }}> Login </button> </div> </div> ); }; export default Login;
3. 个人资料组件 Profile.js
import React from "react"; const Profile = () => { return ( <div> <h1 className="text-3xl">Profile</h1> <h2 className="text-2xl font-semibold">username: </h2> </div> ); }; export default Profile;
4. Contact页面组件
import React from "react"; import Login from "../components/Login"; import Profile from "../components/Profile"; import useUser from "../customHooks/useUser"; const Contact = () => { const { username, showProfile } = useUser(); return ( <div> <Login></Login> {showProfile && <Profile />} <div>username is : {username}</div> </div> ); }; export default Contact;
解答
当前写法的自定义Hook完全实现不了需求
首先明确核心规则:自定义Hook的作用是复用状态逻辑,不是共享状态本身。你现在写的useUser,只要在一个组件里调用一次,就会在对应组件里生成一套完全独立的username和showProfile状态,不同组件调用拿到的状态是完全隔离、互不相通的:
- Login里调用
useUser拿到的状态只属于Login组件,输入用户名、点登录按钮修改的都是Login自己内部的值 - Contact页面里调用
useUser拿到的是另一套全新的状态,和Login里的状态没有任何关联,永远拿不到Login里的更新,Profile自然也不会按预期显示。
不需要必须搭配useContext
不想用useContext的话,用React最基础的状态提升方案就能实现,完全适配你当前组件层级浅的场景,没有额外依赖:
核心思路是把用户相关的状态统一放到最上层的共同父组件(即Contact页面)里管理,再把需要的状态、修改状态的方法通过props传给下层的Login、Profile组件即可。
修改后的代码如下:
1. 修改Contact页面,统一管理状态
import React, { useState } from "react"; import Login from "../components/Login"; import Profile from "../components/Profile"; const Contact = () => { // 状态提升到父组件统一维护 const [username, setUsername] = useState(""); const [showProfile, setShowProfile] = useState(false); return ( <div> {/* 把修改状态的方法通过props传给Login */} <Login setUsername={setUsername} setShowProfile={setShowProfile} /> {/* 把username通过props传给Profile,同时控制显隐 */} {showProfile && <Profile username={username} />} <div>username is : {username}</div> </div> ); }; export default Contact;
2. 修改Login组件,接收props传入的操作方法
import React from "react"; const Login = ({ setUsername, setShowProfile }) => { return ( <div> <div> <input type="text" className="m-2 p-2" placeholder="Enter your email here" onChange={(e) => { setUsername(e.target.value); }} /> </div> <div> <input type="text" className="m-2 p-2" placeholder="Enter your password here" onChange={(e) => {}} /> </div> <div> <button className="m-2 p-2" onClick={() => { setShowProfile(true); }}> Login </button> </div> </div> ); }; export default Login;
3. 修改Profile组件,接收props传入的username
import React from "react"; const Profile = ({ username }) => { return ( <div> <h1 className="text-3xl">Profile</h1> <h2 className="text-2xl font-semibold">username: {username}</h2> </div> ); }; export default Profile;
如果后续组件嵌套层级变深,props需要层层传递太繁琐的时候,再考虑用useContext或者轻量状态管理库即可,当前场景用状态提升是最轻量的实现方案,完全不需要引入useContext。
内容的提问来源于stack exchange,提问作者Muneeb Ejaz
相关产品推荐
相关产品推荐

