我在一个组件中有一个登录/注册表单,我正在尝试相应地更新URL路径。但我有几个要解决的问题。 我正在使用Firebase fetchSignInMethodsForEmail()检查用户是否存在(如果它是一个空数组,则它是新用户)。
new
为真时。它将呈现创建密码输入,并将URL从/ login更新为/ signup。理想的输出:https://id.atlassian.com/login输入任何随机电子邮件地址。 url从登录->注册更改并创建密码输入挂载。当前输出是/ signup仅当我单击用<Link to="/signup">...</>
包裹的Form.Item时才会触发(显示)
new
的操作我尝试使用useRouteMatch来获取路径,如果它等于/ signup,则分派一个动作来切换new
,但是这样做会引起太多的重新渲染错误
if(match.path === "/signup")
{
dispatch(new());
}
当前路线:
<Switch>
<Route path="/signup" component={Login} />
<Route path="/login" component={Login} />
</Switch>
Login.js
const dispatch = useDispatch();
const { new } = useSelector(
state => state.auth
);
const match = useRouteMatch();
if(match.path === "/signup)
{
dispatch(new());
}
return (
<Form>
Email
<Form.Item>
<Input placeholder="Username" />
</Form.Item>
{new ? (
<div>
<Link to="/signup">
Create password
<Form.Item>
<Input.Password placeholder="Password"/>
</Form.Item>
</Link>
</div>
) : (
<div>
Enter your password
<Form.Item>
<Input.Password placeholder="Password"/>
</Form.Item>
</div>
)}
</Link>
{new ? (
<Button>
Sign up
</Button>
) : (
<Button>
Log in
</Button>
)}
</Form>
);
});
答案 0 :(得分:0)
如果我的理解正确,那么您希望在组件的安装阶段之后分派一次此操作。在这种情况下,useEffect()
钩子可能很合适:
import { useEffect } from "react";
...
const match = useRouteMatch();
const onMount = () => {
/* This callback is invoked after mount */
if(match.path === "/signup)
{
dispatch(new());
}
}
/* The effect hook runs the following callback as a side effect */
useEffect(() => {
onMount();
}, []); /* Empty array causes the effect to only run once (on mount) */
有关为何空数组导致效果回调一次触发see this answer的更多信息。
还有一个小建议-考虑将new()
是保留关键字,考虑将new
函数和New
变量重命名为其他名称(也许是new
?)。
希望有帮助!
您可以采用以下“非redux”方法来实现与提供的链接类似的登录/注册流程:
const { useState } from "react";
const AuthForm = () => {
/* Define state shape */
const [state, setState] = useState({
username : "",
password : "",
isNew : false
});
/* Field update helpers */
const setUsername = (username) => setState(s => ({ ...s, username }))
const setPassword = (password) => setState(s => ({ ...s, password }))
const login = async () => {
const { username, password } = state;
/* login logic */
}
const signup = async () => {
const { username, password } = state;
/* signup logic */
}
const checkUsername = async () => {
/*
const response = await fetch("/api/check-username-exists", {
method : "POST",
body : JSON.stringify({ userNameToCheck : state.username })
})
// say that response.found is true when user name we checked
// does exist in database
setState(s => ({ ...s, isNew : !response.found }));
*/
}
const renderFields = () => {
if(!username) {
return <>
<Form.Item>
<Input placeholder="Username"
onChange={e =>setUsername(e.target.value)} />
</Form.Item>
<Button onClick={checkUsername}>
Continue
</Button>
</>
}
else {
return <>
<p>Login as { state.username }</p>
{
state.isNew ? (<div>
<p>Create password</p>
<Form.Item>
<Input.Password placeholder="Password"
onChange={e => setPassword(e.target.value)}/>
</Form.Item>
<Button onClick={signup}>
Sign up
</Button>
</div>) : (<div>
<p>Enter your password</p>
<Form.Item>
<Input.Password placeholder="Password"
onChange={e => setPassword(e.target.value)}/>
</Form.Item>
<Button onClick={login}>
Log in
</Button>
</div>)
}
</>
}
}
return (<Form>{renderFields()}</Form>);
}
请记住,这只是框架代码,旨在说明实现表单的“非redux”方式。它需要通过适当地调用您的后端/ API等来完成,但是希望这能给您一些有关如何实现您的要求的想法:-)
答案 1 :(得分:0)
也许使用本地状态来控制而不是使用redux存储吗?
const [isNew, setIsNew] = useState(location && location.pathname === '/signup')
function handleEmailCheck(event) {
// use Firebase fetchSignInMethodsForEmail() to check the email
// and use setIsNew() & history.pushState() to update address bar render content
}
return (
<Form>
Email
<Form.Item>
<Input placeholder="Username" onBlur={handleEmailCheck} />
</Form.Item>
...