React - HeaderComponent tidak berubah setelah log-in?

Sep 01 2020

Saya memiliki TodoComponentyang telah ditulis untuk menunjukkan tautan tertentu di navbar di HeaderComponent tergantung pada status pengguna saat ini - apakah masuk atau keluar.

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>
        )
    }
}

Saya merasa HeaderComponenttidak merender sendiri lagi setelah pengguna masuk.

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>
        )
    }
}

karena komponen LogIn tidak memaksa? (Haruskah saya memaksa komponen lain? Saya tidak yakin ini adalah cara yang benar untuk melakukan sesuatu)

Cuplikan dari 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)
}

Bagaimana cara membuat pembaruan HeaderComponent (pada dasarnya memanggil rendermetode lagi setelah pengguna log-in?!?!).

PS Saya pikir mungkin ada cara lain untuk melakukannya yang melibatkan secara otomatis melakukan beberapa tindakan berdasarkan suatu peristiwa. Saya hanya tidak tahu bagaimana itu akan cocok dengan apa yang telah saya lakukan sejauh ini. Saya baru mengenal React.

Orang ini menghadapi masalah yang sama (tetapi menjelaskannya dengan buruk IMO): mengaktifkan otentikasi pengguna berbasis tautan menu tidak berfungsi di reactjs

Jawaban

1 AliAbuHijleh Sep 01 2020 at 08:01

Komponen dirender ulang jika mendeteksi adanya perubahan dalam Status atau Properti, inilah yang dilakukan perbandingan dangkal, jadi untuk merender ulang komponen, harus bergantung pada salah satunya, jadi yang dapat Anda lakukan adalah menggunakan isLoginSuccess dan meneruskannya kembali ke TodoComponent dan kemudian kirimkan sebagai props ke HeaderComponent seperti ini:

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>
        )
    }
}

Di LoginComponent

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

Di HeaderComponent, ganti isUserLoggedIn dengan isLoginSuccess:

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>
        )
    }
}

Catatan: Menggunakan Redux atau Context daripada meneruskan props antar komponen akan lebih terstruktur dan mudah ditangani

1 Nalhin Sep 01 2020 at 07:43

Anda tidak boleh menyimpan status autentikasi di kelas eksternal. Deteksi perubahan reaksi terpicu hanya jika status atau props berbeda (perbandingan dangkal). Itu tidak dapat mendeteksi perubahan di kelas eksternal. Keadaan seperti itu dapat, misalnya, dikelola dengan React Context.

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)

Ingatlah untuk membungkus seluruh pohon React Anda dengan AuthProvider.