1

I have the below sample code using react-router and context hooks where I am trying to understand why it behaves differently when I use anchors instead of Link components. The Link components are commented out.

This app just simply displays a screen with an html link where you can click it to display component 2 (component 1 is displayed initially). I am updating the context value in the onClick event for the anchor (I use the setName function to update the name in the context).

When I use anchor tags, it doesn't keep the context value that was updated. So when it goes to component2, the name value in the context displays as person1. However, if I comment out the anchors and use the Link components instead, the context value is updated properly.

Why do the Link components work as expected but not the anchors when updating context?

import React, { useContext, useState } from 'react';
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
import { useHistory } from 'react-router-dom';

const NameContext = React.createContext();

function App() {
  const [name, setName] = useState('name1');

  return (
    <NameContext.Provider value={{ name, setName }}>
      <Router>
        <Route exact path="/" component={Component1} />
        <Route exact path="/component1" component={Component1} />
        <Route exact path="/component2" component={Component2} />
      </Router>
    </NameContext.Provider>
  );
}

function Component1() {
  const { name, setName } = useContext(NameContext);
  const history = useHistory();

  return (
    <>
      <div>This is component 1, name = {name}</div>
      <a href="/component2" onClick={() => setName('name2')}>
        Click to display component 2
      </a>
      {/* <Link
        onClick={() => setName('name2')}
        to={(location) => {
          return { ...location, pathname: '/component2' };
        }}
      >
        Click to display component 2
      </Link> */}
    </>
  );
}

function Component2() {
  const { name, setName } = useContext(NameContext);
  const history = useHistory();

  return (
    <>
      <div>This is component 2, name = {name}</div>
      <a href="/component1" onClick={() => setName('name3')}>
        Click to display component 1
      </a>
      {/* <Link
        onClick={() => setName('name3')}
        to={(location) => {
          return { ...location, pathname: '/component1' };
        }}
      >
        Click to display component 1
      </Link> */}
    </>
  );
}

export default App;
dcp
  • 54,410
  • 22
  • 144
  • 164

2 Answers2

1

An anchor tag reloads the browser by default. If you want to avoid this default behavior you can call the preventDefault method on the onClick event.

react-router doesn't use anchor tags either, so if you want to use anchor tags you have to manually update the history.

<div>This is component 1, name = {name}</div>
<a
  href="/component2"
  onClick={(e) => {
    e.preventDefault();
    setName("name2");
    history.push("/component2");
  }}
>
  Click to display component 2
</a>
Tholle
  • 108,070
  • 19
  • 198
  • 189
0

I had the same issue. Usage of Link or NavLink fixed the problem.

Looks like the ContextProvider is being recreated from scratch when the page reloads so context picks up initial state.

I also found related question React Context API - persist data on page refresh