【问题标题】:React Hooks, React-Router, and UserbaseReact Hooks、React-Router 和用户群
【发布时间】:2021-07-14 04:35:09
【问题描述】:

我正在开发一个 React 网站并学习 React Hooks。在下面的项目中,header.tsxhome.tsx 都是App.tsx 内部的组件。我有一个user 状态对象;即我在所有 3 个文件中加载的 const [user, setUser] = useState<UserResult>();(这是错误的吗?)。

当我在home.tsx 中登录userbase 时,UI 反映了这种变化——home.tsx 中的条件主体反映了user 从未定义到已定义的事实,并显示了注销按钮。

问题来了:我希望header.tsx 也能反映user 的变化;即我希望 header.tsx 能够“监听”user 的变化并将它们反映在 UI 上,但它不会发生。

谁能解释一下?我也不确定userbase.init() 呼叫的位置。

对于某些背景,此项目基于this tutorial。我对其进行了修改以添加 React Router。

App.tsx

import React, { useEffect, useState } from 'react';
import './App.css';
import {Switch, Route} from 'react-router-dom';
import Header from './components/header';
import Home from './components/home';
import userbase, {UserResult} from 'userbase-js';

function App() {
  const [user,setUser] = useState<UserResult>();
  useEffect(() => {
    userbase.init({ appId: process.env.REACT_APP_USERBASE_APP_ID as string })
        .then(session => session.user && setUser(session.user))
  }, []);

  return (
    <div className="App">
      <Header />
      <Switch>
        <Route exact path='/' component={Home} />
      </Switch>
    </div>
  );
}

export default App;

home.tsx

import React, { ChangeEvent, FormEvent, useEffect, useState } from 'react';
import userbase, { UserResult } from 'userbase-js';

function Home() {
    const [user, setUser] = useState<UserResult>();

    const [regForm, setRegForm] = useState<{
        username?: string,
        password?: string
        }>({ username: '', password: '' });
    const handleRegInputChange = (event: ChangeEvent<HTMLInputElement>) =>
        setRegForm({ ...regForm, [event.target.name]: event.target.value });
    
    const handleRegSubmit = (event: FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        if (regForm.username && regForm.password) {
            userbase.signUp({
            username: regForm.username,
            password: regForm.password,
            rememberMe: 'session'
            }).then((ur: UserResult) => setUser(ur))
            .catch(err => alert(err));
        }
    }

    const [loginForm, setLoginForm] = useState<{
        username?: string,
        password?: string
    }>({ username: '', password: '' });

    const handleLoginInputChange = (event: ChangeEvent<HTMLInputElement>) => 
        setLoginForm({ ...loginForm, [event.target.name]: event.target.value });

    const handleLoginSubmit = (event: FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        if (loginForm.username && loginForm.password) {
            userbase.signIn({
                username: loginForm.username,
                password: loginForm.password,
                rememberMe: 'session'
            }).then((ur: UserResult) => setUser(ur))
              .catch(err => alert(err));
        }
    }

    const handleLogout = () => {
        userbase.signOut().then(() => setUser(undefined))
            .catch(err => alert(err));
    }

    return (
        <div>
            <h2>Homepage</h2>
            <a href="/robertbrennan">Show example profile</a>
            <br/>

            {user ? (
                <div>
                    <div>
                        Signed in as {user.username}.{' '}
                        <button onClick={handleLogout}>Log out</button>
                    </div>
                </div>
            ) : (
                <div>
                    <h3>Register</h3>
                        <form onSubmit={handleRegSubmit}>
                            <label>
                                Username:
                                <input type="text" name="username" value={regForm?.username} onChange={handleRegInputChange} />
                            </label>

                            <label>
                                Password:
                                <input type="password" name="password" value={regForm?.password} onChange={handleRegInputChange} />
                            </label>
                            <input type="submit" value="Submit" />
                        </form>

                        <br/><br/><hr/><br/>

                        <h3>Log in</h3>
                        <form onSubmit={handleLoginSubmit}>
                            <label>
                                Username:
                                <input type="text" name="username"
                                value={loginForm?.username} onChange={handleLoginInputChange} />
                            </label>

                            <label>
                                Password:
                                <input type="password" name="password"
                                    value={loginForm?.password} onChange={handleLoginInputChange} />
                            </label>
                            <input type="submit" value="Submit" />
                        </form>
                    </div>
                )}            
        </div>
    )
}

export default Home;

header.tsx

import React, { useEffect, useState } from 'react';
import { UserResult } from 'userbase-js';

function Header(props: any) {
    const [user] = useState<UserResult>();

    return (
        <div>
            <h1><a href="/">Project</a></h1>
            Username: {user?.username}     <---- THIS DOESN'T CHANGE!
            <hr/>
        </div>
    )
}

export default Header;

【问题讨论】:

    标签: reactjs typescript react-router react-hooks


    【解决方案1】:

    工作解决方案:

    App.tsx:

    import React, { useEffect, useState, ChangeEvent, FormEvent } from 'react';
    import './App.css';
    import {Switch, Route} from 'react-router-dom';
    import Header from './components/header';
    import Home from './components/home';
    import Register from './components/register';
    import Login from './components/login';
    import userbase, { UserResult } from 'userbase-js';
    
    function App() {
      const [user, setUser] = useState<UserResult>();
      const [toHome, setToHome] = useState<boolean>(false);
    
      useEffect(() => {
        userbase.init({ appId: process.env.REACT_APP_USERBASE_APP_ID as string })
            .then(session => session.user && setUser(session.user))
      }, []);
    
      const [regForm, setRegForm] = useState<{
        username?: string,
        password?: string
        }>({ username: '', password: '' });
      const handleRegInputChange = (event: ChangeEvent<HTMLInputElement>) =>
          setRegForm({ ...regForm, [event.target.name]: event.target.value });
    
      const handleRegSubmit = (event: FormEvent<HTMLFormElement>) => {
          event.preventDefault();
          if (regForm.username && regForm.password) {
              userbase.signUp({
              username: regForm.username,
              password: regForm.password,
              rememberMe: 'session'
            }).then((ur: UserResult) => {
                setUser(ur)
                setToHome(true);
              }).catch(err => alert(err));
          }
      }
    
      const [loginForm, setLoginForm] = useState<{
          username?: string,
          password?: string
      }>({ username: '', password: '' });
    
      const handleLoginInputChange = (event: ChangeEvent<HTMLInputElement>) => 
          setLoginForm({ ...loginForm, [event.target.name]: event.target.value });
    
      const handleLoginSubmit = (event: FormEvent<HTMLFormElement>) => {
          event.preventDefault();
          if (loginForm.username && loginForm.password) {
              userbase.signIn({
                  username: loginForm.username,
                  password: loginForm.password,
                  rememberMe: 'session'
              }).then((ur: UserResult) => {
                setUser(ur);
                setToHome(true);
              }).catch(err => alert(err));
          }
      }
    
      return (
        <div className="App">
          <Header user={user}/>
          <Switch>
            <Route exact path='/'>
              <Home user={user} setUser={setUser} />
            </Route>
    
            <Route exact path='/register'>
              <Register 
                handleRegSubmit={handleRegSubmit}
                regForm={regForm}
                handleRegInputChange={handleRegInputChange}
                toHome={toHome}
              />
            </Route>
    
            <Route exact path="/login">
              <Login 
                handleLoginSubmit={handleLoginSubmit}
                loginForm={loginForm}
                handleLoginInputChange={handleLoginInputChange}
                toHome={toHome}
              />
            </Route>
          </Switch>
        </div>
      );
    }
    
    export default App;
    
    

    Header.tsx:

    function Header(props: any) {
        return (
            <div>
                <h1><a href="/">Project</a></h1>
    
                {props.user ? (
                    <div>
                        Username: {props.user?.username}
                    </div>
                ) : (
                    <div>
                        Not logged in
                    </div>
                )}
                
                <hr/>
            </div>
        )
    }
    
    export default Header;
    

    Register.tsx:(Login.tsx 非常相似)

    import { Redirect } from 'react-router-dom';
    
    function Register(props: any) {
        return (
            <div>
                {props.toHome ? <Redirect to="/" /> : null}
    
                <h3>Register</h3>
                <form onSubmit={props.handleRegSubmit}>
                    <label>
                        Username:
                        <input type="text" name="username" value={props.regForm?.username} onChange={props.handleRegInputChange} />
                    </label>
    
                    <label>
                        Password:
                        <input type="password" name="password" value={props.regForm?.password} onChange={props.handleRegInputChange} />
                    </label>
                    <input type="submit" value="Submit" />
                </form>
            </div>
        )
    }
    
    export default Register;
    

    【讨论】:

      【解决方案2】:

      我确定您注意到您为用户创建了 2 个 useState,一个在 App.tsx 中,另一个在 header.tsx 中。这是主要问题。如果你想共享用户,将用户从 App 传递到 header 作为 props,而不是创建另一个。

      【讨论】:

        猜你喜欢
        • 2019-08-16
        • 2019-09-30
        • 1970-01-01
        • 2020-08-29
        • 2021-05-13
        • 2018-02-25
        • 2020-07-01
        • 2017-08-28
        • 2017-10-10
        相关资源
        最近更新 更多