1

How to capture when a <Link> is clicked in the component? The first time you click the link, the page loads fine. But when you click the same link a second time, it doesn't reload data. This is the standard result, as it only rerenders when the state/props have changed, but I want to reload new data from the server when the page is revisited.

I've tried using componentDidUpdate but that just ends in an infinite loop. I'm looking for a way to know when react-router-dom has been used and query the server for fresh data.

I've listed the broken down code fragments used below.

<Switch>
    <Route path="/users" component={Users}/>
</Switch>
<Link to={"/users"}>Users</Link>
class Users extends Component {
    componentDidMount() {
        this.getData();
        console.log('componentDidMount');
    }

    componentDidUpdate(nextProps, nextState) {
        console.log('componentDidUpdate');
    }
    getData() {
        axios.get(this.props.table.url).then(response => {
            this.setState({ users: response.data, loading: false})
        })
    }

    render() {
        return( ... )
    }
}
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
Bradmage
  • 1,233
  • 1
  • 15
  • 41
  • when you press the `Link` button, the route has got changed to 'user', every time you change the route, the `componentDidMount` will call. if it's not working on your application, I suggest you create a codesandbox. – nima Nov 02 '21 at 07:52
  • another question, the `Link` button is on another page (route), so when you click it, the route has changedd to `/user` so how can click the `Link` for a second time? is there on the `user` page? – nima Nov 02 '21 at 07:54

1 Answers1

2

I think you've a couple options to "conditionally" handle calling the getData only when accessing the component via the link.

  1. Use some local state to hold a React key value for the link and to send as route state to be checked in the routed component.

    Example:

    import { v4 as uuidV4 } from "uuid";
    
    ...
    
    const [linkKey, setLinkKey] = useState(uuidV4());
    
    ...
    
    <Link
      key={linkKey}
      to={{ pathname: "/users", state: { key: linkKey } }}
      onClick={() => setLinkKey(uuidV4())}
    >
      Users
    </Link>
    

    Users

    componentDidUpdate(prevProps, prevState) {
      if (prevProps.location.state?.key !== this.props.location.state?.key) {
        this.getData();
      }
    }
    
    • Pros: Doesn't remount the target routed component. Doesn't push duplicate paths into the history.
    • Cons: Adds more moving parts, i.e. local state and updaters.
  2. Use a Redirect from a path with a "random" path parameter to the "/users" path.

    import { v4 as uuidV4 } from "uuid";
    
    ...
    
    <Link to={generatePath("/users/:key", { key: uuidV4() })}>Users</Link>
    
    ...
    
    <Switch>
      <Redirect from="/users/:key" to="/users" />
      <Route path="/users" component={Users} />
    </Switch>
    
    • Pros: Less moving parts.
    • Cons: Remounts Users components each time. Pushes each new "instance" into the history stack.

Edit how-to-know-a-react-link-component-has-been-clicked

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • 1
    I ended up using `+ new Date()` to identify a new click, it seemed like less overhead than importing another library. Would you suggest there be a reason to use the uuid over a timestamp? – Bradmage Nov 07 '21 at 00:49
  • 2
    @Bradmage Not a strong reason. GUID's (`uuid`) will guarantee uniqueness, but a timestamp is likely sufficiently unique enough for your needs. A lot of projects I work with already use `uuid` so it's an easy goto. – Drew Reese Nov 07 '21 at 02:42