user10334216
user10334216

Reputation:

Is there a way to stop my header from re-rendering when navigating my site?

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

Answers (2)

user10334216
user10334216

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

Sebastian Hernandez
Sebastian Hernandez

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

Related Questions