javascript - 为什么即使我使用了 useEffect 我的组件也不会重新渲染自己?(React.js)
问题描述
最近,我正在制作我的 web 应用程序,我正在努力解决一个小问题(对我来说并不小)
下面是我的 app.js,我想通过登录/退出状态有条件地渲染 NAV 组件。(如您所见,它位于 Switch 外部!)
<>
<Nav indexStatus={indexStatus} setIndexStatus={setIndexStatus} />
<Index indexStatus={indexStatus} setIndexStatus={setIndexStatus} />
<Switch>
<Route exact path="/" component={Auth(LandingPage,null)}/>
<Route exact path="/login" component={Auth(LoginPage,false)}/>
<Route exact path="/calendar" component={Auth(Calendar,true)} />
<Route exact path="/about" component={Auth(About,false)} />
<Route exact path="/register" component={Auth(RegisterPage,false)}/>
</Switch>
</>
检查登录状态我在用户登录/退出时为 localStorage 提供了 true/false 值
登录:
dispatch(loginUser(body))
.then(response=>{
if(response.payload.loginSuccess){
localStorage.setItem('user',response.payload.loginSuccess)
props.history.push("/")
console.log(props.parentNode)
}else{
alert('login failed')
}
})
登出:
axios.get("/api/users/logout")
.then(res=>{
if(res.data.success){
console.log(res)
history.push('/login')
localStorage.setItem('user','false')
}else{
alert("Logout failed")
}
})
}
我给了 localStorage 值,如下所示:
const [loginStatus,setLoginStatus] =useState(localStorage.getItem('user'))
我用 console.log 检查它,它工作正常
所以我使用 useEffect 更改 loginStatus 值,并重新渲染只有 localstorage 已更改
const checkLoginStatus= localStorage.user
useEffect(()=>{
if(checkLoginStatus==='true'){
setLoginStatus(true)
}else{
setLoginStatus(false)
}
},[checkLoginStatus])
console.log(localStorage.user)
最后,我用 ?: 运算符编写了我的代码,如下所示
return (
<>
{loginStatus ===true ? (
<div>
<div className="nav">
<h2>TITLE</h2>
<div className="buttons">
<div>About</div>
<div>How to use</div>
<button onClick={logoutHandler}>Logout</button>
<StyledLink to="/login"><FontAwesomeIcon icon={faSignInAlt}/></StyledLink>
<button onClick={()=>setIndexStatus(!indexStatus)} >Index</button>
</div>
</div>
</div>)
:
( <div>
<div className="nav">
<h2>TITLE</h2>
<div className="buttons">
<div>About</div>
<div>How to use</div>
<button onClick={logoutHandler}>Logout</button>
<StyledLink to="/login"><FontAwesomeIcon icon={faSignInAlt}/></StyledLink>
<StyledLink to="/register"><FontAwesomeIcon icon={faUserPlus}/></StyledLink>
<button onClick={()=>setIndexStatus(!indexStatus)} >Index</button>
</div>
</div>
</div>
)}
</>
);
}
export default Nav
但是,问题是它只能部分工作,我必须刷新页面才能进行组件条件渲染。我不确定为什么会这样,即使我使用 useEffect 和第二个参数 [checkLoginStatus]
你能告诉我为什么不能正常工作吗?我的逻辑怎么错了?感谢阅读,您的帮助将不胜感激
解决方案
您需要将loginStatus
状态提升到App
父组件,以便可以将状态和更新函数传递给子组件以读取和/或更新。
应用程序
将loginStatus
状态移动到这个父组件。将 传递loginStatus
给Nav
组件以使其处理其条件渲染,并将 传递setLoginStatus
给Login
组件以使其更新状态。请注意,路由已重新排序,因此它们不再需要在exact
任何地方指定道具,它们没有被Auth
HOC 包装,因为这可能会在每个渲染周期创建一个新组件,现在该Login
组件在render
道具上渲染,因此我们可以滑入额外的道具。
const [loginStatus, setLoginStatus] = useState(
() => !!JSON.parse(localStorage.getItem("user")),
);
return (
<>
<Nav
indexStatus={indexStatus}
loginStatus={loginStatus} // <-- pass login status
setIndexStatus={setIndexStatus}
setLoginStatus={setLoginStatus} // <-- pass updater
/>
<Index indexStatus={indexStatus} setIndexStatus={setIndexStatus} />
<Switch>
<Route
path="/login"
render={props => <LoginPage {...props} setLoginStatus={setLoginStatus} />}
/>
<Route path="/calendar" component={Calendar} />
<Route path="/about" component={About} />
<Route path="/register" component={RegisterPage} />
<Route path="/" component={LandingPage} />
</Switch>
</>
);
导航
移除loginStatus
状态并使用传递的loginStatus
值和setLoginStatus
函数来更新父级中的状态。
function Nav({ indexStatus, loginStatus, setLoginStatus, setIndexStatus }) {
const history = useHistory();
const logoutHandler = () => {
...
setLoginStatus(false); // <-- logged out
};
return loginStatus ? (
...
)
: (
...
);
}
登录页面
从 props 中访问setLoginStatus
state updater 功能,并设置用户登录成功的时间。Auth
使用HOC装饰导出(应该为所有需要它的组件完成)。
function LoginPage(props) {
...
const onSubmitHandler=(e)=>{
e.preventDefault();
let body={
email: Email,
password: Password
};
dispatch(loginUser(body))
.then(response=>{
if(response.payload.loginSuccess){
localStorage.setItem('user',response.payload.loginSuccess)
props.setLoginStatus(true); // <-- set logged in
props.history.push("/");
} else {
alert('login failed');
}
});
}
return (
<>
...
</>
);
}
export default Auth(withRouter(LoginPage));
更新
您的组件没有收到传递的道具的原因是因为Auth
HOC 没有传递它们。
export default function(SpecificComponent, option, adminRoute = null) {
...
function AuthenticationCheck(props) { // <-- props
...
return (
<SpecificComponent /> // <-- not passed through
);
}
return AuthenticationCheck
}
应该
export default function(SpecificComponent, option, adminRoute = null) {
...
function AuthenticationCheck(props) { // <-- props
...
return (
<SpecificComponent {...props} /> // <-- passed through
);
}
return AuthenticationCheck
}
推荐阅读
- python - 如果某人具有特定的权限/角色,则使他们免于亵渎过滤器 discord.py
- python - 在熊猫中填充nan时添加偏移量
- azure - 使用数据工厂附加到 azure 数据湖中的文件
- graphql - Strapi Graphql 查询日期和关系
- dynamic - 要嵌入的动态帮助cmd
- c - 从字符串初始化 uInt128 值
- bash - 如何按字符串集中两个不同分隔符之间包含的数值进行bash排序
- python - 错误 take() 不接受布尔索引器
- r - 如何使用 gsub 保留部分字符并删除 R 中的其他任何内容?
- ios - React-Native/XCode/iOS 模拟器 - os/kern 没有可用空间错误