José Carlos
José Carlos

Reputation: 2922

REACT: How to modify styles from another component

The page of my site are build with these components:

<Header />
<Routes />
<Footer />

Obviusly, Header and Footer for all the pages are always the same, but content loaded from Routes is not equal for each page. Ok, I make click over an option of the meny which is in Header component. I go to the page and the name of the option of the menu is correctly underlined.

For example, I'm at home and click over FAQS, I go to FAQS page and FAQS option is underlined.

But, I can go to whatever page from Routes or Footer component. For example, in Footer component I've got an option to go to FAQS page. If I click over this option, I go to FAQS page, but the style of FAQS option in the menu is not updated.

I have checked that in this case are not called methods like componentDidMount or componentDidUpdate.

Therefore, how can I update always the options of the menu which are in Header component?

Edit I:

header.js file

import React, { Component } from "react";
import {Row, Col} from "react-bootstrap";
import "bootstrap/dist/css/bootstrap.min.css";
import { NavLink } from "react-router-dom";
import "../css/header.css";
import logo  from "../images/logo.png";

export class Header extends Component{
    constructor(props){
        super(props);
        this.state = {
            option1: String(window.location).endsWith("/faqs"),
            option2: String(window.location).endsWith("/about"),
            option3: String(window.location).endsWith("/login")
        }
        this.handleClick = this.handleClick.bind(this);
    }

    componentDidMount(){
        window.scrollTo(0, 0);
        console.log("Header.js(ComponentDidMount): Component cargado correctamente!!!");
    }

    componentDidUpdate(){
        window.scrollTo(0, 0);
        console.log("Header.js(componentDidUpdate): Component cargado correctamente!!!");
    }

    removeUnderline(){
        this.setState({
            option1: false,
            option2: false,
            option3: false
        })
    }

    handleClick(event){
        this.removeUnderline();
        if (event.target.id !== "logo"){
            this.setState({
                option1: event.target.id === "option1",
                option2: event.target.id === "option2",
                option3: event.target.id === "option3"
            })    
        }
    }

    render(){
        return(
            <header style = {{width: 100 + "%"}}>
                <Row style = {{margin: 0}}>
                        <Col md = {6} style = {{textAlign: "left"}}>
                            <NavLink to="/" onClick = {this.handleClick}>
                                <img id = "logo" src = {logo} alt = "Breaded" />
                            </NavLink>
                        </Col>
                        <Col md = {6} style = {{textAlign: "right", paddingTop: 25 + "px", paddingRight: 20 + "px"}}>
                            <NavLink to="/faqs" style = {{textDecoration: (this.state.option1) ? "underline" : "none", color: "#000000"}}>
                                <span id = "option1" onClick = {this.handleClick} className = "option-menu">FAQS</span>
                            </NavLink>&nbsp;|&nbsp;
                            <NavLink to="/about" style = {{textDecoration: (this.state.option2) ? "underline" : "none", color: "#000000"}}>
                                <span id = "option2" onClick = {this.handleClick} className = "option-menu">About us</span>
                            </NavLink>&nbsp;|&nbsp;
                            <NavLink to="/login" style = {{textDecoration: (this.state.option3) ? "underline" : "none", color: "#000000"}}>
                                <span id = "option3" onClick = {this.handleClick} className = "option-menu">Login</span>
                            </NavLink>
                        </Col>
                </Row>              
            </header>
        )
    }
}

footer.js file

import React from "react";
import {Row, Col} from "react-bootstrap";
import "bootstrap/dist/css/bootstrap.min.css";
import InstagramIcon from '@material-ui/icons/Instagram';
import FaceboookIcon from '@material-ui/icons/Facebook';
import {NavLink} from "react-router-dom";


export const Footer = () => {
    return(
        <footer style = {{width: 100 + "%", fontSize: 12 + "pt"}}>
            <Row style = {{margin: 0, textAlign: "center", marginTop: 75 + "px"}}>
                <Col md = {12}>
                    <InstagramIcon style = {{fontSize: 28 + "px"}} /> <FaceboookIcon style = {{fontSize: 28 + "px"}} />
                </Col>
            </Row>
            <Row style = {{margin: 0, textAlign: "center", marginTop: 15 + "px", fontWeight: "bold"}}>
                <Col md = {2}><NavLink to="/login" style = {{fontSize: 12 + "pt", color: "#000000", textDecoration: "none"}}>Login</NavLink></Col>
                <Col md = {2}><NavLink to="/contactus" style = {{fontSize: 12 + "pt", color: "#000000", textDecoration: "none"}}>Contact us</NavLink></Col>
                <Col md = {4}><NavLink to="/about" style = {{fontSize: 12 + "pt", color: "#000000", textDecoration: "none"}}>About us</NavLink></Col>
                <Col md = {2}><NavLink to="/faqs" style = {{fontSize: 12 + "pt", color: "#000000", textDecoration: "none"}}>FAQ</NavLink></Col>
                <Col md = {2}><NavLink to="/privacy" style = {{fontSize: 12 + "pt", color: "#000000", textDecoration: "none"}}>Privacy Policy</NavLink></Col>
            </Row>
            <Row style = {{marginTop: 50 + "px", marginBottom: 50 + "px"}}>
                <Col md = {12} style = {{fontSize: 10 + "pt"}}>@Copyright 2020 Breaded</Col>
            </Row>
        </footer>
    )
};

Edit II:

Router are wrapping to each component: Header, Routes and Footer

export const Container = () => {
    return(
        <div>
            <Router>
                <Header />
                <Routes />
                <Footer />
            </Router>            
        </div>
    )

}

routes.js

import React from "react";
import { Home } from "./pages/home/home";
import { About } from "./pages/about";
import  FAQ from "./pages/faq/faq";
import { Plans } from "./pages/plans/plans";
import { P404 } from "./pages/notfound";
import {
    Switch,
    Route,
  } from "react-router-dom";

export const Routes = () => {
    return(
        <Switch>
            <Route exact path="/" component={Home} />
            <Route exact path="/about" component={About} />
            <Route exact path="/faqs" component={FAQ} />
            <Route exact path="/plans" component={Plans} />
            <Route component={P404} />
        </Switch>
    )
}

What am I doing wrong?

Upvotes: 0

Views: 455

Answers (1)

Seth Lutske
Seth Lutske

Reputation: 10676

The way you are applying your css text effects is not ideal. It works in header, but requires a ton of unnecessary logic that is not present in your Footer. And copying all that code would be a big violation of DRY. But even better than abstracting the logic and applying to both components, react router has activeClassName and activeStyle that you can use to style active NavLinks. Just use them similarly in both Header and Footer. Using activeClassName and showing only the parts of the code you need here:

// Header.js

<Col md = {6} style = {{textAlign: "left"}}>
  <NavLink to="/" onClick = {this.handleClick}>
    <img id = "logo" src = {logo} alt = "Breaded" />
  </NavLink>
</Col>
<Col md = {6} style = {...}>
  <NavLink to="/faqs" activeClassName="active-nav-link">
    <span ... >FAQS</span>
  </NavLink>&nbsp;|&nbsp;
  <NavLink to="/about" activeClassName="active-nav-link">
    <span ... >About us</span>
  </NavLink>&nbsp;|&nbsp;
  <NavLink to="/login" activeClassName="active-nav-link">
    <span ... >Login</span>
  </NavLink>
</Col>

You can do the same in Footer:

// Footer.js

<Col md = {2}>
  <NavLink to="/login" activeClassName="active-nav-link">
    Login
  </NavLink>
</Col>
<Col md = {2}>
  <NavLink to="/contactus" activeClassName="active-nav-link">
    Contact us
  </NavLink>
</Col>
<Col md = {4}>
  <NavLink to="/about" activeClassName="active-nav-link">
    About us
  </NavLink>
</Col>
<Col md = {2}>
  <NavLink to="/faqs" activeClassName="active-nav-link">
    FAQ
  </NavLink>
</Col>
<Col md = {2}>
  <NavLink to="/privacy" activeClassName="active-nav-link">
    Privacy Policy
  </NavLink>
</Col>

And then in some associated css file, you can say:

.active-nav-link {
  text-decoration: underline
}

I don't remember if the NavLink returns an <a> or an <li> with a nested <a>, so that might affect how you write your css. You can also use activeStyle and do inline styles as an object, as you had been doing in your original code. Either way will work.

Upvotes: 1

Related Questions