How do I change styles of some shared components in react whose routes I have configured with react-route-dom

Hello Devs,

I am working on a web app that is consisted of few pages and have configured routes with react-route-dom. On each page, I have some shared components such as Navbar and I want them to be styled differently on other pages except the Home page.

How do I get this done? Any help? Thanks

One option might be to look at the pathname returned by the useLocation hook inside the Nav component and apply different styles depending on the path.

I assume you have the Nav component outside the Routes so it is applied to all pages, or using some layout component? Or do you have more than one Nav component?

The Route for the SharedLayout Component is the parent Route for all other Routes and it’s visible on all the other pages. The SharedLayout contains other components including the Nav.

import {BrowserRouter, Routes, Route} from 'react-router-dom'
import Home from './pages/Home'
import About from './pages/About'
import Services from './pages/Services'
import Contact from './pages/Contact' 
import Error from './pages/Error' 
import SharedLayout from './pages/SharedLayout' 
import Footer from './components/Footer'



function App() {
  return (
    <div className="App">
     <BrowserRouter>
      <Routes>
        <Route path='/' element={<SharedLayout />} >
          <Route index element={<Home />} />
          <Route path='/about' element={<About />} />
          <Route path='/services' element={<Services />} />
          <Route path='/contact' element={<Contact />} />
          <Route path='*' element={<Error />} />
        </Route>
      </Routes>
  </BrowserRouter>
  <Footer />
    </div>
  );
}

export default App;

Here is my Nav Component and it is this one I want to give a different style on other pages.

import { NavLink, Link, useLocation} from 'react-router-dom'

const location = useLocation();
const pathName = location.pathname;

const StyledNavbar = () => {
    return (

        <nav id="navbar-container">

            <ul className='main-menu-ul'>
                <li><NavLink className="main-menu" to='/'>Home</NavLink></li>
                <li><NavLink className="main-menu" to='About'>About</NavLink></li>
                <li><NavLink className="main-menu" to='Services'>Services</NavLink>
                    <ul>
                        <li><Link to='#'> BIL QURAN ACADEMY</Link></li>
                        <li><Link to='#'>BIL SCIENCE ACADEMY</Link></li>
                        <li><Link to='#'> BIL TECH</Link></li>
                        <li><Link to='#'> BIL ENGINEERING</Link></li>
                        <li><Link to='#'> BIL COIN</Link></li>
                        <li><Link to='#'> BIL SHOPPING MALL</Link></li>
                    </ul>
                </li>
                <li><NavLink className="main-menu" to='Contact'>Contact</NavLink></li>
            </ul>


        </nav>
    )
}

export default StyledNavbar

I should note that my SharedLayout component contains other components that I wish to give a different style on other pages as well.

import { Outlet } from 'react-router-dom'
import StyledNavbar from '../components/StyledNavbar'
//import Navbar from '../components/Navbar'
import TopHeader from '../components/TopHeader'
const Home = () => {
    return (
        <>
            <TopHeader />
            <StyledNavbar />
            <Outlet />
        </>

    )
}

export default Home

Yes I have two Navs. I’m using css to display a specific one for a specific viewport.

Thanks.

You should still be able to apply different styles to components/JSX depending on the path. Did you look at the hook I linked to?

I can’t really look at your code right now but if you can push it to GitHub that would also be helpful.

Yes I did and I tried to implement it but I’m stuck. If you look at my StyledNavbar Component, you’ll notice that I’m getting the location and pathname, each into a constant.

While waiting until such time that you will be free, I will be focusing on other parts of the project.

Thanks for your hep.

Yes, but you are not using it for anything. You have to create styles or apply classes conditionally based on the path.

I got it. It’s working now. Thanks for your help. I appreciate it.

@lasjorg could you please help me out on this one? I’ve been working on the JavaScript Calculator and I’m currently stuck.

I’ve been trying to code the application so that when I input a number and if there is a number greater than 0 on the display, the inputted number will be appended to the existing one on the display. As much as I have tried, I don’t seem to be making any progress.

import React from 'react'
import '../styles/styles.css'

class Controls extends React.Component {
    constructor(props) {
        super(props)

        this.state = {
            curValue: 0,
            preValue: this.props.defaultValue
        }
        //this.keypadRef = [];
        this.handleClick = this.handleClick.bind(this)
    }
    // getKeypadRefs = (el) => {
    //     this.keypadRef.push(el);
    // }
    

    handleClick(event) {
        this.setState({ curValue: event.target.value })

        if(Number(this.props.defaultValue) > 0 && Number(this.props.defaultValue) <= 9){
            this.props.addDisplayValue(this.state.curValue)
        }else{
            this.props.setDisplayValue(this.state.curValue);
        }
        //console.log("Prevoius value: " + this.state.preValue)
        //console.log("Current value: " + this.state.curValue)s
        this.props.setDisplayValue(this.state.curValue);
    }

    render() {
        //const value = this.state.value
        return (
            <div className="controls-container">
                <button id="clear" onClick={this.props.handleReset}>AC</button>
                <button id="divide"  value='/' onClick={this.handleClick}>/</button>
                <button id="multiply"  value='*' onClick={this.handleClick}>*</button>

                <button id="seven"  value='7' onClick={this.handleClick}>7</button>
                <button id="eight"  value='8' onClick={this.handleClick}>8</button>
                <button id="nine"  value='9' onClick={this.handleClick}>9</button>
                <button id="subtract" value='-' onClick={this.handleClick}>-</button>

                <button id="four"  value='4' onClick={this.handleClick}>4</button>
                <button id="five"  value='5' onClick={this.handleClick}>5</button>
                <button id="six"  value='6' onClick={this.handleClick}>6</button>
                <button id="add"  value='+' onClick={this.handleClick}>+</button>

                <button id="one"  value='1' onClick={this.handleClick}>1</button>
                <button id="two"  value='2' onClick={this.handleClick}>2</button>
                <button id="three"  value='3' onClick={this.handleClick}>3</button>
                <button id="equals"  value='=' onClick={this.handleClick}>=</button>

                <button id="zero"  value='0' onClick={this.handleClick}>0</button>
                <button id="decimal"  value='.' onClick={this.handleClick}>.</button>

            </div>
        )
    }



}



const Display = props => {

    return (
        <div id="display">{props.defaultValue}</div>
    )
}

Display.defaultProps = {defaultValue: 0}

class Calculator extends React.Component {
    constructor(props) {
        super(props)

        this.state = {
            defaultValue: []
        }
        this.handleReset = this.handleReset.bind(this)
        this.setDisplayValue = this.setDisplayValue.bind(this)
        // this.getDisplayValue = this.getDisplayValue.bind(this)

        //this.handleClick = this.handleClick(this);

    }
    handleReset() {
        this.setState({
            defaultValue: 0
        })
    }

    addDisplayValue(value) {
        this.setState({
            defaultValue: [].push(value)
        })
    }

    setDisplayValue(value){
        this.setState({
            defaultValue: value
        })
    }
    // getDisplayValue(){

    // }
    render() {
        return (
            <div id="calculator-container">
                <Display defaultValue={this.state.defaultValue} />
                <Controls defaultValue={this.state.defaultValue} handleReset={this.handleReset} setDisplayValue={this.setDisplayValue} addDisplayValue={this.addDisplayValue} />
            </div>
        )
    }

}

// function appendValue(preValue, curValue){
//     if(preValue > 0 && preValue <= 9){
//         console.log(preValue +""+ curValue)
//         return (preValue +""+ curValue) 
//     }
//     console.log(curValue)
//     return curValue;
// }

export default Calculator

Please create a working example on CodeSandbox, or StackBlitz. Or push the code to GitHub.


Are you talking about setDisplayValue or addDisplayValue?

I have honestly never really used PropTypes much and not for a long time but are you not just checking the default initial value of the props?

Are you actually appending to the state anywhere? Like returning currentState + someValue to setState.

[].push(value) returns the length of the array, is that what you want?

The app is now on CodeSandbox: adoring-worker-tiy2t8 - CodeSandbox

It’s addDisplayValue I was talking about. I want to be able to append a new value to the display if I alredy have an existing value there.

I only used the defaultProps to set a default value for display but It’s not working still. Yes, I’m checking the default initial value and if it’s between 1 and 9 both ends inclusive, the newly entered value from the keypad should be appended to the existing value. And this is what I’ve been struggling with. Everytime I entered a new value it set the display to that new value replacing the existing value.

I want to actually return the currentState + previousState if the value in the display meets the if condition.

I actually wanted to push a new entered value into the array and somehow convert it to string. i was actually trying different approaches since I was confused. [].push(value) wasn’t my initial code.

> Blockquote

I guess I was just confused by the naming. The state value isn’t really a default value if it can change. Sure you can start it out by setting it to a default value but calling something that can be changed by user input a default value is misleading I think.

If the state value is a string you can use normal string concatenation if it’s an array you can use the current value and append the new value, usually using spread is a good approach [...currentState, newValue], if you want the array as a string you can use .join()

Thanks @lasjorg. I appreciate you always. I eventually got the hang of it with your example.

Hi @lasjorg; can I have your input on this one?
The problem I’m trying to solve this time is being able to perform arithmetic operations on the inputted numbers.

This is my algorithm:

  • take the input, split into array
  • find each operator in the array and its position
  • find numbers to the left of each operator as well as the last number
    after the last operator
  • check the type of operators(+, -, /, *)
  • perform operation of an operator with the highest order
  • then next in order and so on
  • finally, show result

But I was stuck somwhere at point 3. Below is my code. I’m trying to solve it with a regular function before taking it to my JavaScript Calculator React App.

function calculator(num){
    const newArr = num.split("")
    newArr.forEach(element => {
        if(num.charCodeAt(element) >= 42 && num.charCodeAt(element) <=  47){
            if(num.charCodeAt(element) === 44 || num.charCodeAt(element) ===  46)
                return
                
            
        }
    });
    console.log(newArr)
}

calculator('5+5')
calculator('10-2')
calculator('2*3')
calculator('12/3')
calculator('5+5*10-2/2*3+12/3')

I’m struggling to convert point number 3 into a working code. Any suggestion? Is my algorithm making any sense?