reactjsreact-routerreact-router-domreactjs-flux

React Router Link component not rendering when redirect


I'm using the material-ui library's component Autocomplete with React flux to create a Search Bar that finds users.

I want every option to be a link to a page with more information of that user. Currently, it only works the first time I click on an option. Every time after that it changes the URL but the page is not re-rendered.

This is the Autocomplete code:

export function SearchBar() {
  const [url, setUrl] = useState("/perfil/");

  const { store, actions } = useContext(Context);

  useEffect(() => {
    actions.search();
  }, [url]);

  const artistas = store.artistas.slice();

  return (
    <Autocomplete
      id="autocomplete"
      freeSolo
      disableClearable
      options={artistas}
      getOptionLabel={(option) => option.nombre + " " + option.apellido}
      renderOption={(option) => (
        <Link
          className="text-black text-decoration-none"
          onClick={() => setUrl(url + option.id)}
          to={`/perfil/${option.id}`}
        >
          {option.nombre} {option.apellido}
        </Link>
      )}
      renderInput={(params) => (
        <TextField
          {...params}
          size="small"
          placeholder="Search for your artist"
          margin="normal"
          variant="outlined"
          InputProps={{ ...params.InputProps, type: "search" }}
        />
      )}
    />
  );
}

This is the page where it is redirected:

export const Perfil = () => {
  const { user_id } = useParams();

  return (
    <>
        <About user_id={user_id} />
        <Galeria user_id={user_id} />
    </>
  );
};

The flux action is this:

  search: async () => {
        try {
          const response = await fetch(
            process.env.BACKEND_URL + "/api/artistas"
          );
          const data = await response.json();
          setStore({
            artistas: data,
          });
        } catch (error) {
          console.log("Error loading message from /api/artistas", error);
        }
      }

At last, this is the layout page:

return (
    <div>
      <BrowserRouter basename={basename}>
        <ScrollToTop>
          <Navbar />
          <Routes>
            <Route element={<Inicio />} path="/" />
            <Route element={<Login />} path="/login" />
            <Route element={<Registro />} path="/registro" />
            <Route element={<Perfil />} path="/perfil/:user_id" />
            <Route element={<Producto />} path="/producto/:theid" />
            <Route
              element={<ConfiguracionUsuario />}
              path="/configuracion/:theid"
            />
            <Route element={<h1> Not found! </h1>} />
          </Routes>{" "}
          <Footer />
        </ScrollToTop>{" "}
      </BrowserRouter>{" "}
    </div>
  );

Solution

  • I fixed it. The problem was in the Galeria component. It took the id by props:

      useEffect(() => {
        actions.producto_galeria(props.user_id);
      }, []);
    

    But we should have used a stored variable with the ID that changes on every click with a flux action, instead of props. So now, I get the ID as follows:

    flux new action:

    get_artista_id: (artista_id) => {
        setStore({ artista_id: artista_id });
    }
    

    Link new onClick:

     <Link
      className="text-black text-decoration-none"
      onClick={() => {
        actions.get_artista_id(option.id);
      }}
      to={`/perfil/${option.id}`}
    >
      {option.nombre} {option.apellido}
    </Link>
    

    useEffect on Galeria to detect the change on the ID:

      useEffect(() => {
        actions.producto_galeria(store.artista_id);
      }, [store.artista_id]);