trungdq88 / react-router-page-transition

Highly customizable page transition component for your React Router
https://trungdq88.github.io/react-router-page-transition
MIT License
543 stars 53 forks source link

withRef: true not working #29

Closed cupojoe closed 6 years ago

cupojoe commented 6 years ago

Has anyone had issues with the <PageTransition> component throwing an error:

Uncaught Error: To access the wrapped instance, you need to specify { withRef: true } as the fourth argument of the connect() call.

I have nested routes and if I use the <PageTransition> at the top level I get duplicate entering components instead of one exiting and one entering. If I lower the <PageTransition> to the nested route I get the error above. Any ideas? I'm using {withRefs: true} in the connect function.

cupojoe commented 6 years ago

I think I might have found a bit more on this. So, as long as you are only wrapping on redux connect it works, but if you are wrapping on another component too, like I'm doing redux connectedRouterRedirect, then it can't find the children. Not sure if this is an easy fix.

trungdq88 commented 6 years ago

So, as long as you are only wrapping on redux connect it works, but if you are wrapping on another component too, like I'm doing redux connectedRouterRedirect, then it can't find the children

That looks like the issue.

<PageTransition> need access to the rendered DOM to be able the change the classes. If you have wrapped your component by your custom HOC (in this case your connectedRouterRedirect, you'll need to define a method getWrappedInstance in your component, just like react-redux's connect() does.

class connectedRouterRedirect extends React.Component {
  // ... (your code)
  getWrappedInstance() {
    return this.ref; // Return ref to the DOM.
  }
}
cupojoe commented 6 years ago

I'll check on this in a little bit, but I believe what. is happening is that there is a double wrapping, so when the getWrappedInstance() method gets called on the auth wrapper what it gets back is the connect wrapper, instead of the actual react component inside the connect. I'll double check and confirm in a bit.

cupojoe commented 6 years ago

@trungdq88 I think this is accurate. The getWrappedInstance method works on the auth wrapper, but it returns the connect wrapper under it. Not sure if this worth exploring. Here is how my router is setting this up:

const userIsNotAuthenticated = connectedRouterRedirect({
  redirectPath: (state, ownProps) => locationHelper.getRedirectQueryParam(ownProps) || '/discover',
  allowRedirectBack: false,
  authenticatedSelector: state => !state.session,
  wrapperDisplayName: 'UserIsNotAuthenticated'
});

const userIsAuthenticated = connectedRouterRedirect({
  redirectPath: '/login',
  authenticatedSelector: state => state.session,
  wrapperDisplayName: 'UserIsAuthenticated'
});

export default (
  <Route path="/" component={App}>
    <Route component={PrimaryLayout}>
      <Route
        path="discover"
        component={userIsAuthenticated(HomePage)}
        onEnter={() => mpTrack('Discover Feed Page Visit')}
      />
      <Route
        path="about"
        component={AboutPage}
        onEnter={() => mpTrack('About Page Visit')}
      />
      <Route
        path="activity"
        component={userIsAuthenticated(ActivityPage)}
        onEnter={() => mpTrack('User Activity View')}
      />
      <Route
        path="c/:id/:slug/jobs/:jobId/:jobSlug"
        component={userIsAuthenticated(JobDetailsPage)}
        onEnter={() => mpTrack('Job Detail Page Visit')}
      />
      <Route
        path="c/:id/:slug/jobs"
        component={userIsAuthenticated(JobsPage)}
        onEnter={() => mpTrack('Jobs Page Visit')}
      />
      <Route
        path="privacy-policy"
        component={PrivacyPolicyPage}
        onEnter={() => mpTrack('Privacy Policy Page Visit')}
      />
      <Route
        path="signout"
        component={LogoutPage}
        onEnter={() => mpTrack('User Sign Out')}
      />
      <Route
        path="terms-of-use"
        component={TermsOfUsePage}
        onEnter={() => mpTrack('Terms of Use Page Visit')}
      />
    </Route>
    <Route component={ProfileLandingLayout}>
      <Route
        path="c/:id/:slug"
        component={userIsAuthenticated(CompanyProfilePage)}
        onEnter={() => mpTrack('Company Page Visit')}
      />
      <Route
        path="profile"
        component={userIsAuthenticated(UserProfilePage)}
        onEnter={() => mpTrack('User Profile Own Page Visit')}
      />
      <Route
        path="u/:id/:slug"
        component={userIsAuthenticated(UserProfilePublicPage)}
        onEnter={() => mpTrack('User Profile Public Page Visit')}
      />
    </Route>
    <Route component={SecondaryLayout}>
      <Route
        path="login"
        component={userIsNotAuthenticated(LoginPage)}
        onEnter={() => mpTrack('Login Page Visit')}
      />
      <Route
        path="profile/edit"
        component={userIsAuthenticated(UserProfileEditPage)}
        onEnter={() => mpTrack('User Profile Edit Page Visit')}
      />
      <Route
        path="reset-password"
        component={ResetPasswordPage}
        onEnter={() => mpTrack('Reset Password Page Visit')}
      />
      <Route
        path="signup"
        component={SignupPage}
        onEnter={() => mpTrack('Create Account Page Visit')}
      />
    </Route>
    <Route
      path="search/:query"
      component={userIsAuthenticated(SearchResultsPage)}
      onEnter={() => mpTrack('Search Page Visit')}
    />
    <Route component={PrimaryLayout}>
      <Route
        path="*"
        component={NotFoundPage}
        onEnter={() => mpTrack('404 Page Visit')}
      />
    </Route>
  </Route>
);

As you can see the component gets wrapped in the authentication and then the component itself is wrapped also in connect().

trungdq88 commented 6 years ago

If your getWrappedInstance method do not return a DOM, <PageTransition> won't work properly. You can try move the <PageTransition> component to somewhere that directly wrap your DOM (may be inside connectedRouterRedirect?).

trungdq88 commented 6 years ago

Close due to inactive. Feel free to reopen if you still have this problem.