Code Monkey home page Code Monkey logo

Comments (18)

ganlub avatar ganlub commented on August 20, 2024 4

@faceyspacey I ended up going with the initialDispatch: false, I wasn't aware of this property, so I removed the redux-action-buffer because it's not needed at all.

In case it helps somebody, persistStore allows you to add a callback when the re-hydration is complete, so there you can call initialDispatch(). There's as well a gap of a few milliseconds while all of this happens, so I added a spinner so it won't render a blank screen. I have a page reducer (I took this approach from the official demo) and I set the initial state like this:

export default (state = LOADING, action = {}) => {
  return components[action.type] || state
}

const components = {
  ROUTE_HOME,
  ROUTE_LOGIN,
  NOT_FOUND
}

from redux-first-router.

brownbl1 avatar brownbl1 commented on August 20, 2024 2

Not to worry though. Seems like the callback behavior is coming back: rt2zz/redux-persist#408

from redux-first-router.

faceyspacey avatar faceyspacey commented on August 20, 2024

I don't currently know, but I need to find out. Can you try applying it directly to the demo in isolation and see if there are any problems:

https://github.com/faceyspacey/redux-first-router-demo

Probably the best way to figure out how redux-persist plays with SSR + rehydration.

from redux-first-router.

ganlub avatar ganlub commented on August 20, 2024

I implemented it along with RFR and everything works as expected. There will be actions being fired before the re-hydration happens so you will need to rather use this or this.

@faceyspacey it would be nice to have it on the demo!

from redux-first-router.

chapati23 avatar chapati23 commented on August 20, 2024

Here's how I solved it. Maybe it's helpful to somebody. Had to use the cookies adapter for redux-persist so I had the state I'm interested in on the server already. Not sure if it's really the best solution but it works for me :)

// src/routesMap.js
// …
    thunk: (dispatch, getState) => {
      const { steps } = getState() // up to you to handle via standard redux techniques
      canContinueIf(steps.someStepCompleted, dispatch)
    }
// …
const canContinueIf = (stepCompleted, dispatch) => {
  if (!stepCompleted) {
    const action = redirect({ type: 'SOME_DEFAULT_ROUTE' })
    dispatch(action)
  }
}
// server/configureStore.js
export default async (req, res) => {
  // …
  const cookies = req.cookies
  const parsedCookies = {}
  Object.entries(cookies).forEach(([key, value]) => {
    const decodedKey = decodeURIComponent(key)
    const keyWithoutReduxPersistPrefix = decodedKey.replace(/reduxPersist:/, '')
    if (key !== 'reduxPersistIndex') {
      parsedCookies[keyWithoutReduxPersistPrefix] = JSON.parse(value)
    }
  })
  const preLoadedState = { ...parsedCookies } // onBeforeChange will authenticate using this
  // …
}
// src/configureStore.js
export default (history, preLoadedState) => {
  // …
  const store = createStore(rootReducer, preLoadedState, enhancers)

  if (!isServer) {
    persistStore(store, {
      blacklist: ['location', 'page'],
      storage: new CookieStorage()
    })
  }
// …
}
// server/index.js
import cookieParser from 'cookie-parser'
// …
app.use(cookieParser())
// …

from redux-first-router.

faceyspacey avatar faceyspacey commented on August 20, 2024

excellent! ...i think it's likely the only way--how else are we going to guarantee the client state becomes redux state on the server? Headers doesn't work, since direct visits can't contain headers like ajax requests in SPAs. Cookies is the only option.

Very well done. I'll probably even document this approach at some point. If you're up to, feel free to make a pr with a new .md in the docs folder. Feel free to give yourself credit with a link, etc.

from redux-first-router.

faceyspacey avatar faceyspacey commented on August 20, 2024

...perhaps a more formal solution/package would let you blacklist keys so huge amounts of domain state isn't stored in cookies (which would slow down requests). We only want UI state after all.

Or perhaps there is a reason to have domain state--black/whitelist options would let the user determine what should be stored in cookies.

from redux-first-router.

faceyspacey avatar faceyspacey commented on August 20, 2024

@ganlub so the idea is that to buffer and delay actions that enhancers like the one from RFR might trigger, so that when route thunks are called, they have everything they need from redux-persist as well? Very pro!

from redux-first-router.

chapati23 avatar chapati23 commented on August 20, 2024

@faceyspacey created a little doc locally. tried creating a feature branch, commiting with npm run cm and then pushing but don't have permissions. what's the workflow?

from redux-first-router.

chapati23 avatar chapati23 commented on August 20, 2024

figured it out, here goes: #78

from redux-first-router.

faceyspacey avatar faceyspacey commented on August 20, 2024

excellent. was just writin.

from redux-first-router.

faceyspacey avatar faceyspacey commented on August 20, 2024

im just gonna close this, since we have the PR (doing a little cleanup)

from redux-first-router.

brownbl1 avatar brownbl1 commented on August 20, 2024

I know you closed this, @faceyspacey, but I wanted to add a few more details that I've been teasing out over the past hour.

First, I liked the idea of using redux-action-buffer as @ganlub suggested so I went down that route. My idea was that I could add the action buffer middleware to queue up and fire all actions (including the initial location action) only after the persist/REHYDRATE action is fired. The catch though is I was trying this with the redux-persist@next package. The problem is that in the v5 rewrite of redux-persist, they also dispatch a persist/PERSIST action before the persist/REHYDRATE. It seems that persist/REHYDRATE isn't fired until persist/PERSIST is fired. See this issue for reference: rt2zz/redux-action-buffer#14

I've created a tentative pull request in redux-action-buffer to effectively whitelist certain actions (namely persist/PERSIST) which fixes this use case of redux-action-buffer.

Using this approach, if we set up our configureStore to look like this:

const middlewares = applyMiddleware(
	createActionBuffer(REHYDRATE, null, [PERSIST]),
	middleware,
	thunk,
	logger
)

I get the desired be behavior and my action sequence looks like:
persist/PERSIST
persist/REHYDRATE
HOME // redux-first-router action
INCIDENTS_FETCHED

Does that make sense and do you see any issues with this? I'm really only messing around with it in the browser (not native or server at this point). It's possible I've missed a bigger problem here but this seems to solve all of my issues with not having access to the persisted store in onBeforeChange or route thunks.

It should probably be stated clearly that I haven't yet had a chance to see how this should work with the universal suite you've been working on. My very limited use case is that I am making an ajax request to a lambda function which returns a jwt that I'd like to store in localStorage. I don't have a server at all at this point, and I'm not trying to store all of my app state in localStorage; just the user token/info.

Also, thanks for the great work on this router!

from redux-first-router.

faceyspacey avatar faceyspacey commented on August 20, 2024

Thanks for taking the time to do this analysis!

...so i havent had time to focus on redux-persist personally unfortunately. So that means I'm lacking in answers.

But I can say this: i dont really like the fact that now u gotta add createActionBuffer. It's just one more thing. It's the reverse steve-jobs "one more thing" where u dont get something u want in that "one more thing." A never ending set of negative "one more things" lol.

So to me that's usually a signal to dig my heals in at some point and take a holistic approach and see if we can do "better."

I still can barely wrap my head around what the buffer thing is doing since i havent tried it--I get it, it's delaying actions. But maybe there's a better way. Why can't we just get a damn callback or await on redux persist somehow. Maybe we can get a PR into the v5 that lets u do this. If this is a genuine problem, they should build in a solution to it, not provide 3rd party hacks via additional buffer middleware.

Feel free to let me know if I'm far off in my limited birds eye perspective.

from redux-first-router.

brownbl1 avatar brownbl1 commented on August 20, 2024

No problem. Just thought it might be helpful to someone else, but I agree it feels like a hack and should be viewed as a stop-gap solution. And I'd love to have all of this become effortless, as do you!

I don't think you're far off in seeing that this approach isn't ideal, but I'm not really sure how an await/hook into redux-persist would look.

Maybe the persistStore method could return an onRehydrated callback on the returned Persistor type? See: https://github.com/rt2zz/redux-persist/blob/v5/docs/api.md#persiststorestore

Then we could hook into that inside onBeforeChange et. al. Other than that, though, not 100% sure how it would work, and haven't taken the time to dig into the redux-persist code yet.

My PR should be merged shortly though over on rt2zz/redux-action-buffer#15 so that solution should work for now for my and maybe other use cases.

from redux-first-router.

brownbl1 avatar brownbl1 commented on August 20, 2024

@ganlub Are you using the v5 branch of redux-persist? If so, I couldn't find the callback as I believe it's being removed. A few people have suggested adding it back, which I would be in favor of.

from redux-first-router.

ganlub avatar ganlub commented on August 20, 2024

@itslittlejohn Oh I see, no I'm using v4.8.3.
I haven't had the chance of checking v5.

from redux-first-router.

waynebloss avatar waynebloss commented on August 20, 2024

I tried out the callback that you pass to persistStore and I found that it only fires once.

I need to do something every time REHYDRATE happens (to check if the user is logged out). So the action buffer should work for me.

EDIT: The action buffer actually only fires the callback once as well, when it releases the buffer. So, I ended up just handling REHYDRATED in one of my reducers and then setting a timeout to fire an action to redirect the user to the login page when rehydration logged them out.

from redux-first-router.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.