Reputation:
I'm creating a website using React JS, React-Router-Dom, React-Redux & React-Persist.
I set up a login & sign up page with firebase. When a user logs in or signs up, I would like to have their display name in the header-component. Using my current method, I realized that when a user is logged in, the header component re-renders every time, however, I'm not too fond of that since it doesn't make navigating my website smooth. When the user is not logged in, the header component doesn't re-render.
I'm relatively new to React JS and was reading the documentation & googling other similar problems, but I can not find a solution and having a hard time approaching this. Any assistance or suggestions would be greatly appreciated!
Below are my index.js, App.js, header.component.jsx
index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import "bootstrap/dist/css/bootstrap.css";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { store, persistor } from "./redux/store";
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<PersistGate persistor={persistor}>
<App />
</PersistGate>
</BrowserRouter>
</Provider>,
document.getElementById("root")
);
App.js
import React from "react";
import { Route, Switch, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import "./App.css";
import Header from "./components/header/header.component";
import Footer from "./components/footer/footer.component";
import HomePage from "./pages/homepage/homepage.page";
import SponsorsPage from "./pages/sponsors/sponsors.page";
import TeamPage from "./pages/team/team.page";
import AccountPage from "./pages/myaccount/myaccount.page"
import SignInAndSignUpPage from "./pages/sign-in-and-sign-up/sign-in-and-sign-up.page";
import { auth, createUserProfileDocument } from "./firebase/firebase.util";
import { setCurrentUser } from "./redux/user/user.action";
import { createStructuredSelector } from "reselect";
import { selectCurrentUser } from "./redux/user/user.selector";
class App extends React.Component {
unSubscribeFromAuth = null;
componentDidMount() {
const { setCurrentUser } = this.props;
this.unSubscribeFromAuth = auth.onAuthStateChanged(async (userAuth) => {
if (userAuth) {
const userRef = await createUserProfileDocument(userAuth);
userRef.onSnapshot((snapShot) => {
setCurrentUser({
id: snapShot.id,
...snapShot.data(),
});
});
}
setCurrentUser(userAuth);
});
}
componentWillUnmount() {
this.unSubscribeFromAuth();
}
render() {
return (
<div>
<Header />
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/sponsors" component={SponsorsPage} />
<Route exact path="/team" component={TeamPage} />
<Route exact path="/myaccount" component={AccountPage} />
<Route
exact
path="/signin"
render={() =>
this.props.currentUser ? <Redirect to="/" /> : <SignInAndSignUpPage/>
}
/>
</Switch>
<Footer />
</div>
);
}
}
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
setCurrentUser: (user) => dispatch(setCurrentUser(user)),
});
export default connect(mapStateToProps, mapDispatchToProps)(App);
header.component.jsx
import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectCurrentUser } from "../../redux/user/user.selector";
import { auth } from "../../firebase/firebase.util";
import { ReactComponent as Logo } from "../../assets/eaglerocketry-icon.svg";
import Navbar from "react-bootstrap/Navbar";
import Nav from "react-bootstrap/Nav";
import "./header.style.scss";
const Header = ({ currentUser }) => (
<Navbar collapseOnSelect expand="md" bg="light" fixed="top">
<Navbar.Brand className="mr-auto">
<Logo className="logo" />
</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="pl-md-4">
<Nav.Link href="/">HOME</Nav.Link>
<Nav.Link href="/outreach">OUTREACH</Nav.Link>
<Nav.Link href="/team">TEAM</Nav.Link>
<Nav.Link href="/sponsors">SPONSORS</Nav.Link>
</Nav>
<Nav className="ml-auto">
{currentUser ? <Nav.Link href="/myaccount">{currentUser.displayName}</Nav.Link> : null}
{currentUser ? (
<Nav.Link onClick={() => auth.signOut()}>SIGN OUT</Nav.Link>
) : (
<Nav.Link href="/signin">SIGN IN</Nav.Link>
)}
</Nav>
</Navbar.Collapse>
</Navbar>
);
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
});
export default connect(mapStateToProps)(Header);
Upvotes: 1
Views: 1818
Reputation:
being relatively new React JS I found a solution to my question.
I had to make my functional component into a class and have a local state that stores the name & use that in my render() function instead of this.props.currentUser.displayName.
class Header extends React.Component {
constructor(props){
super(props);
this.state = {
name: this.props.currentUser.displayName,
};
}
Upvotes: 0
Reputation: 11
Every time that a prop (in this case currentUser) changes in a stateless component (like your Header component) is gonna re-render, because you are using that prop inside or your component, not only for displaying the displayName, but also to conditionally render some links ( <Nav.Link> ). So it is inevitable that a react component doesn't re-render if its props change.
Upvotes: 1