React router - read query string value

React router - read query string value
0

#1

I don’t know if this is possible but I hope it is. I am building an application and somehow I need to read the path value of the query string, the component looks like this:

render() {
    return (
      <React.Fragment>
        <Header
          changeColor={this.handleHeaderColor}
          headerDark={this.state.headerDark}
        />
        <main>
          <Switch>
            <Route path="/lookbook-chels" component={Lookbook} />
            <Route path="/journal-chels" component={Journal} />
            <Route path="/cart" component={Cart} />
            <Route path="/shop-chels" component={Shop} />
            <Route path="/not-found" component={NotFound} />
            <Route path="/" exact component={Home} />
            <Redirect to="not-found" />
          </Switch>
        </main>
      </React.Fragment>
    );
  }
}

The thing is that my header is slightly different when it’s rendered in the Home component. I have a solution, but I just realized that it’s not going to work because I will have to pass the handlerHeaderColor method to every anchor/Link in my web app, it’s not very reliable.

So I’m wondering if there is a way that I can read the path of these Routes so I can use that value to change the state of my Header component.

I would like to do something like this:

if (this.state.path !== "/") // Then change Header state...

I know my components have default props (location, path, etc…) when you use Route, but my Header component is not a child of any of these Routes, so how can I have access to these props?


#2

The only way to have the prop shared between two components like that is to put it in a parent component (in pure react). Since it looks like you’re creating the path values in this component already, you can transform them into a state. An array of paths that can be passed to Header and to each Route.


#3

Let me correct myself, I would like the path value of each Route component in my stateful most parent component (App), this way I can control the state of my Header, which is also a child of App.

So, for example, when I go to the “shop” route component, I would like to get the value of the path in my App state.


#4

Ok I think I understood now. Have you checked the location object? It is passed as a prop and you have the pathname.


#5

Yeah I’ve seen the location property, I guess my question would be, how can I know, from my parent stateful component (App) the path current location?, like am I home ("/"), shop ("/shop"), etc.? Because my Header component behaves differently based on the path. If I’m home, the Header is light, else, the Header is dark.

I mean I have a method that triggers whenever a link item is clicked, this way I can handle the header change, but if I have 15+ links item in my application, this approach looks like a very bad idea.


#6

Ok… Just so we are in the same page, the component you’re showing in the first post is the App component? Every route component do have access to the location property, but not the App. If the App component had access to the location prop then you could easily check what path you are. Is that correct?

If that’s the case, you can wrap your App component with withRouter. It will provide the location object you need in the App. Let me know if this helps.


#7

You have it correct, but I am following the example from the link you provided (Except for the propTypes) and there are no props in the App component when I check in the console. It’s weird that you use a variable to wrap the parent component and then you don’t use the variable at all (following the example).


#8

You pointed me to the right direction, it’s just that it seems the example is outdated or perhaps I missed something, either way I kept digging and found this, instead of following the example from the link you provided, I actually had to do it like this export default withRouter(App);

And just as you said, that would give me the props from each child route, and that’s exactly what I needed. Instead of having a click event on every Link of my app (unthinkable), I could solve it like this:

const Header = ({ pathName }) => {
  const headerClass =
    pathName === "/"
      ? "header padding-container"
      : "header header--dark padding-container";

  return (...)
}

Of course, I could me the above code less repetitive, but oh well, maybe later. Thanks a lot dude, you have all the answers to my questions :laughing:


#9

Glad you solve this. withRouter is a high-order-function, it works like a decorator, it wraps your component and provide some stuff for it. You can actually use it in a lot of ways, so the link I provide is not outdated.

It even give us the compose way of doing things, not sure if you heard it before? It comes from the recompose library, which is a library I highly recommend. It allows you to write all your components as simple pure functions, like you did with your Header but allows the component to have state, lifecycles methods and it all. You’ll never come back to classes after you use it. Just a tip :smiling_face_with_three_hearts:


#10

Never header about the term of compose way of doing things. I’m fairly new to React so there are a lot of things I don’t know.

Is there any advantages of using functional components over classes? I find myself using functional components because I try to keep a single source of truth as long as I can, so if I’m creating a stateless component, a functional components is more readable and easier to work with than a class component.


#11

There isn’t any additional functionality. Using functional components without recompose you can’t do a lot of things class components do have like state or lifecycle methods. With recompose you can write all your components in the functional way, which, for me at least, is way more clean and readable.

If you want to keep a single source of truth, them I’d use redux. That way your app state stays in redux, and only the component’s necessary state stays in the component itself. I just love working with react/redux, and recompose make it that much better.

But don’t overwhelm yourself, it’s best to add one thing at a time :+1:


#12

Yeah Redux is on my list of things to learn, but I would like to learn Node.js first, I think I can manage with React in the meantime, working only with React in 2/3 projects should be a good practice for me to know when I really need Redux.