skip to Main Content

I have a News component which takes some props, and I want to make it re-render whenever I click on <Link /> with the corresponding category props. It updates the URL but does not re-render the component.

<Routes>
  <Route
    path="/"
    element={
      <News
        country={this.country}
        apiKey={this.API_KEY}
        pageSize={this.pageSize}
        category="general"
      />
    }
  />
  <Route
    path="/business"
    element={
      <News
        country={this.country}
        apiKey={this.API_KEY}
        pageSize={this.pageSize}
        category="business"
      />
    }
  />
  <Route
    path="/entertainment"
    element={
      <News
        country={this.country}
        apiKey={this.API_KEY}
        pageSize={this.pageSize}
        category="business"
      />
    }
  />
</Routes>

These are my <NavLink />

<li className="nav-item">
  <NavLink className="nav-link" aria-current="page" to="/">
    Home
  </NavLink>
</li>
{this.props.categories.map((category) => {
  return (
    <li key={category} className="nav-item">
      <NavLink to={`/${category}`} className="nav-link">
        {category[0].toUpperCase() +
          category.slice(1, category.length)}
      </NavLink>
    </li>
  );
})}

2

Answers


  1. Chosen as BEST ANSWER

    We can simply add a unique key in the element component. It will re-render every time with some different props.

    <Route
        path="/business"
        element={
          <News
            key="business" { /*A unique key */}
            country={this.country}
            apiKey={this.API_KEY}
            pageSize={this.pageSize}
            category="business"
          />
        }
      />
    

  2. react-router/react-router-dom optimizes rendering by keeping the same component instance mounted even though it is rendered on multiple routes. This is a performance optimization to save unmounting and remounting the same component only to pass it different props values. In other words, the component remains mounted even though the route changed, and should handle the props value updating in the componentDidUpdate lifecycle method or useEffect hook with dependency.

    Based on the routes and the passed props it’s really that this News component has some dependency on the category prop as that’s the only prop I see that is different.

    The News component should likely have a useEffect hook with a dependency on this category prop to run/load whatever data is different based on this different prop value.

    Example:

    const News = ({ apiKey, category, country, pageSize }) => {
      useEffect(() => {
        // a dependency value changed, rerun some logic
      }, [apiKey, category, country, pageSize]);
    
      ...
    };
    

    If News is a React class-based component then it should implement the componentDidUpdate method.

    class News extends React.Component {
      ...
    
      componentDidUpdate(prevProps) {
        const { apiKey, category, country, pageSize } = this.props;
    
        if (
          category !== prevProps.category
          /* || other props change conditions */ 
        ) {
          // a dependency value changed, rerun some logic
        }
      }
    
      ...
    };
    

    Also, based on this, since it also appears that the category and the URL path match, for the most part, you could likely also make the code more dry by rendering a single route with the category as a route path parameter, and applying the same useEffect hook logic to rerun the logic that depends on the category value.

    Example:

    <Routes>
      <Route
        path="/:category?"
        element={
          <News
            country={this.country}
            apiKey={this.API_KEY}
            pageSize={this.pageSize}
          />
        }
      />
    </Routes>
    
    import { useParams } from 'react-router-dom';
    
    const News = ({ apiKey, country, pageSize }) => {
      const { category = "general" } = useParams();
    
      useEffect(() => {
        // a dependency value changed, rerun some logic
      }, [apiKey, category, country, pageSize]);
    
      ...
    };
    

    Again, if News is a Class-component, then use the appropriate componentDidUpdate lifecycle method and implement a custom withRouter Higher Order Component in order to inject the category route path parameter as a prop.

    Using a React key on the News component should only be used as a last resort since it invloves actually tearing down, e.g. unmounting, and remounting the component which is a lot more work than simply rerendering the component with updated prop values.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search