Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Parent Component completely reconstructed when using Redirect

I am trying to utilize nested routes in order to maintain the appearance of a parent component on screen, and as the user navigates left and right in a tab structure, the content in that tabbed interface updates. I do not want the parent component to remount or even re-render, only it's children to change. This is a completely keyboard-based navigation system, so we are not using Links or click events, just hitting left/right/up/down/enter on the keyboard.

Unfortunately, I cannot share my exact code for privacy reasons, but here is the general code structure (obviously not compilable, just to get the gist of what our architecture is like).

in App.js

class App extends Component {
  render() {
    return (
      <div className="App">
        <Switch>
          <Route
            path="/"
            exact
            match={ true }
            component={ () => <MainMenu/> }
          />
          <Route
            path="/category/:uniqueID"
            exact
            component={ () => <CategoryComponent childArray=[child1, child2, child3] /> }
          />
      />
        </Switch>
      </div>
    );
  }
}

in CategoryComponent.js

class CategoryComponent extends Component {
  render() {
    var childRoutes;
    this.props.childArray.forEach(child => {
      childRoutes.push(
        <Route
          key=child.id
          path={ `${this.props.match.path}/${child.path}` }
          component={ () => <ChildComponent/> }
        />
      );
    });

    return (
      <div className="CategoryComponent">
        ... // a bunch of UI stuff goes here, including the navigation for the child components
        <Switch>
          { childRoutes }
        </Switch>
      </div>
    );
  }
}

and finally, in the ChildComponent.js

class ChildComponent extends Component {
  shouldComponentUpdate(nextProps) {
    // because this navigation is done exclusively by keyboard,
    // each child has a property of selected or not that it gets from its parent,
    // so only the currently selected one should actually be doing the redirect
    if (!this.props.isSelected && nextProps.isSelected) {
      this.redirect = true;
    }
  }
  render() {
    var redirect;
    if (this.redirect) {
      redirect = 
        <Redirect
          to={ `${this.props.match.path}/${this.props.thisChildPath}` }
        />;
    }

    return (
      <div className="ChildComponent">
        { redirect }
      </div>
    );
  }
}

Hopefully all of the above made sense, it's as simple as I think I can make it from our crazy complex application. Basically:

  • we have an app with a route that utilizes a unique ID, ie. myApp.com/category/1234
  • inside of this category, we have some tabs to navigate to, like blue, red, yellow, and for each one, we want to nest the route inside of the above and wind up with something like myApp.com/category/1234/blue, which will update only a part of the screen

The problem I am having is that it seems no matter where I place the redirects, if I use exact or (non-exact paths), or if I use push as true in the Redirect, the parent component ALWAYS remounts. I end up with an entirely new parent component, which will wipe out certain elements saved in local state. The App never remounts, but the Parent Component does. I only want the Child Components to remount, the parent should stay exactly as is. Originally the Category component was even a Higher Order Component, and we switched this to just one normal component class, but with or without conditionally rendering specific cases, didn't seem to make any different either.

Also, I have been playing around with this codesandbox, and adapted the original code to more closely match my project and utilize both links and redirects, and the parent app component never seemed to remount. So...it SEEMS like it's possible, I'm just not sure what I'm doing wrong.

Any help would be greatly appreciated :) thanks!

like image 458
cherries Avatar asked Nov 27 '18 11:11

cherries


People also ask

How does react redirect work?

The Redirect component was usually used in previous versions of the react-router-dom package to quickly do redirects by simply importing the component from react-router-dom and then making use of the component by providing the to prop, passing the page you desire to redirect to.

How do I redirect to another component in react?

To redirect to another page on button click in React: Use the useNavigate() hook, e.g. const navigate = useNavigate(); . Call the navigate() function, passing it the path - navigate('/about') . The navigate() function lets us navigate programmatically.

How do I redirect back to previous page in react?

To go back to the previous page, pass -1 as a parameter to the navigate() function, e.g. navigate(-1) . Calling navigate with -1 is the same as hitting the back button. Similarly, you can call the navigate function with -2 to go 2 pages back.


1 Answers

This helped me out a ton: https://github.com/ReactTraining/react-router/issues/6122

I realized that our App's Switch Routing was using component, which was causing the reconstruction every time. By switching those all to render, the problem was solved :D

So App.js became this:

class App extends Component {
  render() {
    return (
      <div className="App">
        <Switch>
          <Route
           path="/"
            exact
            match={ true }
            render={ () => <MainMenu/> }
          />
          <Route
            path="/category/:uniqueID"
            exact
            render={ () => <CategoryComponent childArray=[child1, child2, child3] /> }
          />
      />
        </Switch>
      </div>
    );
  }
}
like image 109
cherries Avatar answered Oct 18 '22 18:10

cherries