React - HeaderComponent tidak berubah setelah log-in?
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
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
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.