如何在组件安装上更新路径?

时间:2019-12-23 19:35:30

标签: javascript reactjs redux react-router-dom

我在一个组件中有一个登录/注册表单,我正在尝试相应地更新URL路径。但我有几个要解决的问题。 我正在使用Firebase fetchSignInMethodsForEmail()检查用户是否存在(如果它是一个空数组,则它是新用户)。

  1. 道具new为真时。它将呈现创建密码输入,并将URL从/ login更新为/ signup。理想的输出:https://id.atlassian.com/login输入任何随机电子邮件地址。 url从登录->注册更改并创建密码输入挂载。

当前输出是/ signup仅当我单击用<Link to="/signup">...</>包裹的Form.Item时才会触发(显示)

  1. 如果我直接输入path / signup,如何触发redux来调度将更新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>
  );
});

2 个答案:

答案 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>
    ...