admin管理员组

文章数量:1410717

I want to pull subreddits and show to user as a list. When user changes subreddit from options menu, I push state to browser history.

Live Demo:

Reproduction:

  1. Open above link
  2. Select frontend from list. When listed select reactjs again.
  3. You will see URL changes (appends subreddit)
  4. Now press back button of browser and forward.
  5. You will see that URL changes but content is the same.

Live Editor:

In AsyncApp.js Line 36:

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

How can I show previous or next cached/state to user when back/forward pressed? Can someone edit my online app to show me the correct way? I am trying to solve this since 2 days and no luck.


I need to do this without page refresh. (async)

I want to pull subreddits and show to user as a list. When user changes subreddit from options menu, I push state to browser history.

Live Demo: https://react-7qfrxx.stackblitz.io

Reproduction:

  1. Open above link
  2. Select frontend from list. When listed select reactjs again.
  3. You will see URL changes (appends subreddit)
  4. Now press back button of browser and forward.
  5. You will see that URL changes but content is the same.

Live Editor: https://stackblitz./edit/react-7qfrxx

In AsyncApp.js Line 36:

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

How can I show previous or next cached/state to user when back/forward pressed? Can someone edit my online app to show me the correct way? I am trying to solve this since 2 days and no luck.


I need to do this without page refresh. (async)

Share Improve this question edited Apr 14, 2019 at 6:47 Dennis asked Apr 13, 2019 at 17:58 DennisDennis 1,9756 gold badges26 silver badges41 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 3

Previous solution didn't work, so here's my updated answer: I think your best bet is to listen to the LOCATION_CHANGE action type of connected-react-router and to dispatch you selectSubreddit there. Using LOCATION_CHANGE is undocumented in the connected-react-router project, however the docs of the old project react-router-redux does mention it.

We can actually create a middleware function to acplish this:

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);
}

Next, add it to your other middleware:

import thunkMiddleware from 'redux-thunk'

import { createBrowserHistory } from 'history'
import { applyMiddleware, pose, 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,
    pose(
      applyMiddleware(
        listenRouteMiddleware,
        routerMiddleware(history), // for dispatching history actions
        thunkMiddleware
        // ... other middlewares ...
      ),
    ),
  )

  return store
}

Alter the change handler to only push the new url upon selecting an option:

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

That's all! To see a working example, check out: Editor, App

You need to fetch the data based on the Route instead of the state. While selecting the dropdown, only change the route. You can use connected-react-router for listening to the URL change. When a route is changed it'll fetch the data based on the Route.

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
  }
}

Here's the fork. https://stackblitz./edit/react-wxfdea

Here's the fixed App. https://react-wxfdea.stackblitz.io

URLs are updated.

The problem with your current solution is that you're storing the selectedSubreddit state value in two places - Redux and the url. This sort of state duplication is generally to be avoided. You're using the connected-react-router lib so you're not having too many problems yet, but in a larger app this sort of thing could get quite difficult to manage.

Also you have two routes in your app, /frontend and /reactjs, but you aren't defining any <Route/> ponents.

I think your ponent structure should look more like,

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

And then in the ponentDidMount of <SubReddit/> you simply inspect the location prop that the router supplies for the currently selected subreddit. Changing to a different subreddit is then simply a matter of navigating (use react-router's <Link/> ponent for this). In this way the url bees to source of truth for the currently selected subreddit.

Redux is pletely overkill for just managing the list of subreddit posts, but fair enough if this an exercise to use it for practice.

The reason this is not working for you is because you are only reading the subreddit name from Redux state, and not looking at the URL. You can actually get the URL from the state, by looking at the location in the router.

So an easy fix is, instead of storing and reading the selectedSubreddit as a separate part of redux state, always calculate it based on the URL. Change your mapStateToProps in AsyncApp.js as follows:

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

本文标签: