React-ログイン後にHeaderComponentは変更されませんか?

Sep 01 2020

TodoComponentログインかログアウトかを問わず、ユーザーの現在の状態に応じて、HeaderComponentのナビゲーションバーに特定のリンクを表示するように作成されたものがあります。

class TodoApp extends Component {
    render = () => {
        return (
            <div className="TodoApp">
                <Router>
                        <HeaderComponent />
                        <Switch>
                            <Route path="/" exact component={LoginComponent} />
                            <Route path="/login" exact component={LoginComponent} />
                            <AuthenticatedRoute path="/welcome/:name" exact component={WelcomeComponent} />
                            <AuthenticatedRoute path="/todos/" exact component={ListTodosComponent} />
                            <AuthenticatedRoute path="/logout" exact component={LogoutComponent} />
                            <Route component={ErrorFuncComponent} />
                        </Switch>
                        <FooterComponent />
                </Router>
            </div>
        )
    }
}

HeaderComponentユーザーがログインした後、が再びレンダリングされないように感じます。

class HeaderComponent extends Component {

    render() {
        
        const isUserLoggedIn = AuthenticationService.isUserLoggedIn()
        console.log(isUserLoggedIn)

        return (
            <header>
                <nav className="navbar navbar-expand-md navbar-dark bg-dark">
                    <div><a href="http://localhost:3000" className="navbar-brand">Todo Management</a></div>
                    <ul className="navbar-nav">
                        {isUserLoggedIn && <li><Link className="nav-link" to="/welcome/in28minutes">Home</Link></li>}
                        {isUserLoggedIn && <li><Link className="nav-link" to="/todos">Todos</Link></li>}
                    </ul>
                    <ul className="navbar-nav navbar-collapse justify-content-end">
                        {!isUserLoggedIn && <li><Link className="nav-link" to="/login">Login</Link></li>}
                        {isUserLoggedIn && <li><Link className="nav-link" onClick={AuthenticationService.logoutAuthenticatedUser} to="/logout">Logout</Link></li>}
                    </ul>
                </nav>
            </header>
        )
    }
}

ログインコンポーネントが強制されないためですか?(他のコンポーネントを強制する必要がありますか?これが正しい方法かどうかわかりません)

のスニペット LoginComponent.jsx

handleLoginButtonClick = () => {

    if (this.state.username === 'zaid' && this.state.password === 'khan') {
        AuthenticationService.registerAuthenticatedUser(this.state.username, this.state.password)
        // window.location.reload(false);
        this.props.history.push(`/welcome/${this.state.username}`) //String templating //this.props.history.push("/welcome/"+this.state.username)
        this.setState(
            { isLoginSuccess: true, isLoginFailed: false }, function () {
                console.log(this.state);
            }
        )
    }
    else {
        this.setState(
            { isLoginSuccess: false, isLoginFailed: true }, function () {
                console.log(this.state);
            }
        )
    }
    // console.log(this.state)
}

HeaderComponentを更新するにはどうすればよいですか(基本的renderに、ユーザーがログインした後にメソッドを再度呼び出しますか?!?!)。

PSイベントに基づいて何らかのアクションを自動的に実行する別の方法があるかもしれないと思います。私はそれが私がこれまでにしたことにどのように適合するかを知りません。Reactは初めてです。

この男は同じ問題に直面しました(しかし、IMOの説明が不十分でした):メニューリンクベースのユーザー認証を有効にすると、reactjsで機能しません

回答

1 AliAbuHijleh Sep 01 2020 at 08:01

状態または小道具の変更を検出すると、コンポーネントは再レンダリングされます。これは、浅い比較で行われることです。したがって、コンポーネントを再レンダリングするには、コンポーネントが1つに依存している必要があるため、isLoginSuccessを使用してパスバックします。 TodoComponentに送信し、次のように小道具としてHeaderComponentに送信します。

class TodoApp extends Component {
    state = {isLoginSuccess:false}
    render = () => {
        return (
            <div className="TodoApp">
                <Router>
                        <HeaderComponent isLoginSuccess={this.state.isLoginSuccess}/>
                        
                        <Switch>
                            <Route path="/" exact component={() => <LoginComponent isAuthed={true} onLogin={(status)=> this.setState({isLoginSuccess:status})}/>} />
                            ...
                </Router>
            </div>
        )
    }
}

ではLoginComponent

handleLoginButtonClick = () => {
    if (this.state.username === 'zaid' && this.state.password === 'khan') {
        ...
        this.props.onLogin(true);
        ...
    }
    else {
        this.props.onLogin(false);
        ...
    }
}

HeaderComponent isLoginSuccessでisUserLoggedIn置き換えます。

class HeaderComponent extends Component {

    render() {
    let { isLoginSuccess } = this.props;
        ...
        return (
            <header>
                <nav className="navbar navbar-expand-md navbar-dark bg-dark">
                    <div><a href="http://localhost:3000" className="navbar-brand">Todo Management</a></div>
                    <ul className="navbar-nav">
                        {isLoginSuccess && <li><Link className="nav-link" to="/welcome/in28minutes">Home</Link></li>}
                        ...
                </nav>
            </header>
        )
    }
}

注:コンポーネント間で小道具を渡す代わりにReduxまたはContextを使用すると、より構造化され、処理が簡単になります

1 Nalhin Sep 01 2020 at 07:43

認証ステータスを外部クラスに保持するべきではありません。React Change検出は、状態または小道具が異なる場合にのみトリガーされます(浅い比較)。外部クラスの変更を検出することはできません。このような状態は、たとえば、ReactContextで管理できます。

const AuthContext = React.createContext()

function AuthProvider(props) {
  const login = () => {}
  const register = () => {}
  const logout = () => {} 
  const isLoggedIn = ()=>{}
  return (
    <AuthContext.Provider value={{data, login, logout, register, isLoggedIn }} {...props} />
  )
}

export function withAuthContext(Component) {
    return function WrapperComponent(props) {
        return (
            <AuthContext.Consumerr>
                {state => <Component {...props} context={state} />}
            </AuthContext.Consumer>
        );
    };
}

export {AuthProvider, withAuthContext}
class HeaderComponent extends Component {

    render() {
        
        const isUserLoggedIn = props.context.isLoggedIn()

        return (
            <header>
                <nav className="navbar navbar-expand-md navbar-dark bg-dark">
                    <div><a href="http://localhost:3000" className="navbar-brand">Todo Management</a></div>
                    <ul className="navbar-nav">
                        {isUserLoggedIn && <li><Link className="nav-link" to="/welcome/in28minutes">Home</Link></li>}
                        {isUserLoggedIn && <li><Link className="nav-link" to="/todos">Todos</Link></li>}
                    </ul>
                    <ul className="navbar-nav navbar-collapse justify-content-end">
                        {!isUserLoggedIn && <li><Link className="nav-link" to="/login">Login</Link></li>}
                        {isUserLoggedIn && <li><Link className="nav-link" onClick={props.context.logout} to="/logout">Logout</Link></li>}
                    </ul>
                </nav>
            </header>
        )
    }
}

export default withAuthContext(HeaderComponent)

Reactツリー全体をでラップすることを忘れないでくださいAuthProvider