LINUX.ORG.RU

history.push() - адресная строка обновляется, страница остается прежней

 


0

1

Minimal reproducible example на основе примера

package.json

{
  "name": "React Router - No Match (404)",
  "version": "0.0.0",
  "description": "A simple example deployed using react-codesandboxer",
  "main": "index.js",
  "dependencies": {
    "react-router-dom": "^5.3.0",
    "react-scripts": "latest",
    "react": "latest",
    "react-dom": "latest",
    "history": "latest"
  }
}

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './example';

ReactDOM.render(
<App />,
document.getElementById('root')
);

example.js

import React from "react";
import {
  HashRouter as Router,
  Route,
  Link,
  Switch,
  Redirect
} from "react-router-dom";
import { createHashHistory } from "history";

// You can use the last <Route> in a <Switch> as a kind of
// "fallback" route, to catch 404 errors.
//
// There are a few useful things to note about this example:
//
// - A <Switch> renders the first child <Route> that matches
// - A <Redirect> may be used to redirect old URLs to new ones
// - A <Route path="*> always matches

export default function NoMatchExample() {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/old-match">Old Match, to be redirected</Link>
          </li>
          <li>
            <Link to="/will-match">Will Match</Link>
          </li>
          <li>
            <Link to="/will-not-match">Will Not Match</Link>
          </li>
          <li>
            <Link to="/also/will/not/match">Also Will Not Match</Link>
          </li>
        </ul>

        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/old-match">
            <Redirect to="/will-match" />
          </Route>
          <Route path="/will-match">
            <WillMatch />
          </Route>
          <Route path="*">
            <NoMatch />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

function Home() {
  return <h3>Home</h3>;
}

function WillMatch() {
  return <h3>Matched!</h3>;
}

let history = createHashHistory();

function goToMain() {
  history.push("/");
}

function NoMatch() {
  let location = history.location;

  return (
    <div>
      <h3>
        No match for <code>{location.pathname}</code>
      </h3>
      <button onClick={goToMain}>Go home</button>
    </div>
  );
}

Если нажать ссылку Will Not Match, а затем кнопку Go home, якорь в адресной строке браузера обновится, а страница не перерисуется.

Если поменять версию history на 4.10.1, как сказано здесь, то от перехода по ссылкам location.pathname перестанет обновляться.

Что я делаю не так? Неужто все так, это библиотека не так написана?

cast javascript Princesska onetoomany

★★★

Что я делаю не так?

Не используешь хук useHistory из react-router-dom.

Если не нравятся хуки, то раньше можно было обернуть в withRouter из react-router-dom и получать history через пропсы.

vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 1)
Ответ на: комментарий от firkax

Как будто кто-то этого не знает.

Я временно и сделал

function goToMain() {
  window.location.hash = "/";
}

function NoMatch() {
  let hash = window.location.hash;

  return (
    <div>
      <h3>
        No match for <code>{hash.slice(1)}</code>
      </h3>
      <button onClick={goToMain}>Go home</button>
    </div>
  );
Так работает.

Я так понимаю, смысл этой либы только в том, чтобы абстрагироваться от конкретной реализации history, чтобы hash history можно было легко поменять на browser history, например.

damix9 ★★★
() автор топика
Ответ на: комментарий от vvn_black

Hooks can only be called inside of the body of a function component.
React Router ships with a few hooks that let you access the state of the router and perform navigation from inside your components.

А мне надо получить/поменять якорь из функций вне всех React-компонентов.

damix9 ★★★
() автор топика
Ответ на: комментарий от damix9

¯\(ツ)

Кмк, если брать реакт, то уж и использовать его «по-современному» - функции и хуки.Так проще.

vvn_black ★★★★★
()
Ответ на: комментарий от Princesska

А как надо, вот так?

function NoMatch() {
  let history = useHistory();
  let location = history.location;

  return (
    <div>
      <h3>
        No match for <code>{location.pathname}</code>
      </h3>
      <button onClick={() => history.push("/")}>Go home</button>
    </div>
  );
}

damix9 ★★★
() автор топика
Ответ на: комментарий от damix9

Конкретно в этом примере тебе вообще программатически взаимодействовать с history не нужно:

// пишу не в IDE, с косяками разберёшься сам
const NoMatch = () => {
  const { pathname } = useLocation();

  return (
    <div>
      <h3>
        No match for <code>{pathname}</code>
      </h3>
      <Link to="/">Go home</Link>
    </div>
  );
}

Бывают случаи, когда нужно, но сейчас тебе с этим заморачиваться будет излишне.

Princesska ★★★★
()

vvn_black, Princesska, только в реальном приложении компонентов, подобных NoMatch из этого примера, 100500. И все они классовые, и во всех в них вызывается функция, объявленная вне всех классов и функций. Так вот из нее надо обновлять window.location.hash.

Идея в чем ...

function goTo() {
    return function(path) {
        history.push(path)
    }
}
...
<button onClick={goTo("/")}>Go home</button>

Именно поэтому я хочу обновлять якорь из функции вне всех React-компонентов. Если history получать через useHistory или через пропсы, то во первых придется много всего переписать, а во вторых код станет не меньше, а больше. А если все оставить как есть, то ловлю указанный баг (или не баг).

damix9 ★★★
() автор топика
Ответ на: комментарий от Princesska

Даже если использовать ссылки, а не кнопки везде где только можно, то без программного обновления hash все равно не обойтись - надо же как-то перекинуть пользователя на другую страницу после успешной отправки данных формы.

damix9 ★★★
() автор топика
Ответ на: комментарий от damix9

Не вспомню за шесть лет (поначалу, чсх, с классами) командной разработки на реакте, чтобы <NoMatch /> был не именно такой, какой я тебе написал, и чсх, ты сам же признаёшь, что конкретно здесь обращаться к history.push() тебе не нужно.

Греп из реального проекта:

const fetcher = <T1, T2>(
  history: ReturnType<typeof useHistory>,
  payload: /* ... */
) => {
  /* ... */
  return API.post<Payload<T1, T2>>(
    route.getPath({ /* ... */ }),
    body
  ).then(({ data }) => {
    history.push(data.meta.url); /* <---- работает преспокойнейше */

    /* ... */

    return transformPayload(data, /* ... */);
  });
};

УМВР, используй useHistory

Princesska ★★★★
()
Ответ на: комментарий от damix9

вызывается функция, объявленная вне всех классов и функций. Так вот из нее надо обновлять

Если history получать через useHistory или через пропсы, то во первых придется много всего переписать, а во вторых код станет не меньше, а больше

Если обернуть компонент в withRouter (или через свою хелпер-обёртку использовать эти компоненты) не так уж и сильно что-то поменяется в коде. А там уже и передавать history из пропсов в ту функцию.

Но, кмк, нормальный вариант заканчивается на useHistory.

vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 4)
23 июля 2022 г.
Ответ на: комментарий от damix9

У цукера нету ни одного профессионала. Вместо того, чтобы нормальный бек использовать - накачал пых стероидами. Реакт - вообще кал, и history.push вместо класса навигации, и jsx наркоманский вместо темплейтов

DumLemming ★★★
()
Ответ на: комментарий от DumLemming

Я про тех, кто сайт делал, в который я добавляю фичи.

damix9 ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.