Содержимое не изменяется, когда выполняется перемотка назад / вперед в браузере с данными состояния в React Redux

#javascript #reactjs #redux

#javascript #reactjs #redux

Вопрос:

Я хочу извлекать подредакты и показывать пользователю в виде списка. Когда пользователь изменяет subreddit из меню опций, я помещаю состояние в историю браузера.

Живая демонстрация: https://react-7qfrxx.stackblitz.io

Воспроизведение:

  1. Откройте ссылку выше
  2. Выберите frontend из списка. При появлении списка выберите reactjs снова.
  3. Вы увидите изменения URL (добавляет subreddit)
  4. Теперь нажмите кнопку назад в браузере и вперед.
  5. Вы увидите, что URL-адрес меняется, но содержимое остается прежним.

Живой редактор: https://stackblitz.com/edit/react-7qfrxx

AsyncApp.js В Line 36 :

 this.props.dispatch(push('/'   nextSubreddit))
 

Как я могу показать предыдущее или следующее кэшированное / состояние пользователю при нажатии назад / вперед? Может ли кто-нибудь отредактировать мое онлайн-приложение, чтобы показать мне правильный путь? Я пытаюсь решить эту проблему с 2 дней и безуспешно.


введите описание изображения здесь

Мне нужно сделать это без обновления страницы. (асинхронный)

Ответ №1:

Предыдущее решение не сработало, так что вот мой обновленный ответ: я думаю, вам лучше всего прослушать LOCATION_CHANGE тип действия connected-react-router и отправить вам selectSubreddit там. Использование LOCATION_CHANGE не задокументировано в connected-react-router проекте, однако в документах старого проекта react-router-redux упоминается об этом.

На самом деле мы можем создать функцию промежуточного программного обеспечения для достижения этой цели:

 import { LOCATION_CHANGE } from 'connected-react-router'
import { selectSubreddit } from './actions';

export const listenRouteMiddleware = ({ dispatch, getState }) => (next) => (action) => {
  if (action.type === LOCATION_CHANGE) {
    const { pathname } = action.payload.location;
    if (pathname !== '/') {
      const pathArray = pathname.split('/');
      const selectSub = pathArray[pathArray.length - 1];
      next(action); // before dispatch, otherwise history breaks
      dispatch(selectSubreddit(selectSub));
      return;
    }
  }
  next(action);
}
 

Затем добавьте его в другое промежуточное программное обеспечение:

 import thunkMiddleware from 'redux-thunk'

import { createBrowserHistory } from 'history'
import { applyMiddleware, compose, createStore } from 'redux'
import { routerMiddleware } from 'connected-react-router'
import createRootReducer from './reducers'
import { listenRouteMiddleware } from './middleware';
export const history = createBrowserHistory()

export default function configureStore(preloadedState) {
  const store = createStore(
    createRootReducer(history), // root reducer with router state
    preloadedState,
    compose(
      applyMiddleware(
        listenRouteMiddleware,
        routerMiddleware(history), // for dispatching history actions
        thunkMiddleware
        // ... other middlewares ...
      ),
    ),
  )

  return store
}
 

Измените обработчик изменений, чтобы только нажимать новый URL-адрес при выборе опции:

 handleChange(nextSubreddit) {
  this.props.dispatch(push('/'   nextSubreddit))
}
 

Вот и все! Чтобы увидеть рабочий пример, ознакомьтесь с: Редактор, приложение

Комментарии:

1. Это не работает для меня. Когда я нажимаю назад / вперед, содержимое не меняется. Если я обновлю страницу, тогда это сработает. Я не говорю «при загрузке страницы». Допустим, пользователь загрузил страницу, а затем изменил параметры. Когда он возвращается назад, а затем переходит вперед, содержимое не меняется. Я добавил GIF.

2. @Pratha извините за это, вы правы. Мой предыдущий ответ был совершенно неправильным. Пожалуйста, смотрите Мой обновленный ответ для правильного решения

3. Спасибо. Это вызывает бесконечный обратный цикл. Вы можете возвращаться миллионы раз (между интерфейсом и reactjs), но не можете идти вперед. ответ @reflexgravity работает отлично. Но мне понравился стиль промежуточного программного обеспечения. Однако, как я уже сказал, вы можете возвращаться бесконечно, но не можете идти вперед. (Даже в его ответе я могу вернуться к «/», но с вашим я могу выбирать только между вариантами)

4. @Pratha просто исправил это, пришлось перейти к следующей части (действие). Я редактировал, как вы прокомментировали: D

Ответ №2:

Вам нужно извлекать данные на основе маршрута, а не состояния. При выборе выпадающего списка измените только маршрут. Вы можете использовать connected-react-router для прослушивания изменения URL. При изменении маршрута он будет извлекать данные на основе маршрута.

 function mapStateToProps(state) {
  var { selectedSubreddit, postsBySubreddit } = state;

  // Listen to the connected-react-router API for URL change.
  selectedSubreddit = state.router.location.pathname === "/" ? "reactjs" : state.router.location.pathname.split("/")[1];

  const { isFetching, lastUpdated, items: posts } = postsBySubreddit[
    selectedSubreddit
  ] || {
    isFetching: true,
    items: []
  }

  return {
    selectedSubreddit,
    posts,
    isFetching,
    lastUpdated
  }
}
 

Вот вилка.
https://stackblitz.com/edit/react-wxfdea

Вот исправленное приложение. https://react-wxfdea.stackblitz.io

URL-адреса обновляются.

Комментарии:

1. Это не работает для меня. Когда я нажимаю назад / вперед, содержимое не меняется. Если я обновлю страницу, тогда это сработает. Я не говорю «при загрузке страницы». Допустим, пользователь загрузил страницу, а затем изменил параметры. Когда он возвращается назад, а затем переходит вперед, содержимое не меняется. Я добавил GIF.

2. Теперь проблема устранена, я добавил прослушиватель к API connected-react-router, который будет извлекать данные при изменении маршрута. Смотрите Обновленный код и ссылки выше.

Ответ №3:

Проблема с вашим текущим решением заключается в том, что вы сохраняете значение selectedSubreddit состояния в двух местах — Redux и url. Такого рода дублирования состояний, как правило, следует избегать. Вы используете connected-react-router библиотеку, поэтому у вас пока не так много проблем, но в более крупном приложении с подобными вещами может быть довольно сложно справиться.

Также у вас есть два маршрута в вашем приложении, /frontend и /reactjs , но вы не определяете какие-либо <Route/> компоненты.

Я думаю, что ваша структура компонентов должна выглядеть больше как,

 <Router>
  <>
    <Route exact path="/frontend" component={SubReddit}/>
    <Route exact path="/reactjs" component={SubReddit}/>
  </>
</Router>
 

А затем в componentDidMount of <SubReddit/> вы просто проверяете location prop, который маршрутизатор предоставляет для выбранного в данный момент subreddit. Тогда переход на другой subreddit — это просто вопрос навигации ( <Link/> для этого используйте компонент react-router). Таким образом, URL-адрес становится источником истины для выбранного в данный момент subreddit.

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

Комментарии:

1. Спасибо. Например, эти 2 варианта. Этот маршрут динамичен и может быть любым. Он тоже может быть вложенным ( reactjs/another/dir/ . Так что мне нужно успеть все .

2. Хорошо, но это не должно мешать вам использовать <Route/> компонент — они поддерживают динамические пути.

Ответ №4:

Причина, по которой это не работает для вас, заключается в том, что вы читаете только имя subreddit из состояния Redux и не просматриваете URL-адрес. На самом деле вы можете получить URL-адрес из состояния, посмотрев на местоположение в маршрутизаторе.

Таким образом, простое решение заключается в том, чтобы вместо сохранения и чтения selectedSubreddit как отдельной части состояния redux всегда вычислять его на основе URL. Измените свой mapStateToProps вход AsyncApp.js следующим образом:

   const { router, postsBySubreddit } = state;
  const selectedSubreddit = router.location.pathname.substr(1) || 'reactjs';
 

Комментарии:

1. К сожалению, это работает только при начальной загрузке страницы. Что я пытаюсь сделать, так это обработать изменения в переходе назад / вперед без обновления страницы и снова отобразить предыдущее или следующее состояние. Я добавил GIF-файл экрана. Пожалуйста, взгляните на это.

2. @Pratha Я не уверен, почему это не сработало для вас. Вот ответвление вашей исходной проблемы с моими предложенными изменениями: stackblitz.com/edit/react-9c7m23 и вы можете увидеть, как это работает здесь react-9c7m23.stackblitz.io .