brocoders / redux-async-connect

It allows you to request async data, store them in redux state and connect them to your react component.
645 stars 103 forks source link

Help needed: dipatch, getState not being made available to action creators #99

Open mnazim opened 7 years ago

mnazim commented 7 years ago

dipatch and getState not being made available to async action creators during server side rendering. Everything seems to work fine on client side. I am including the relevant parts of the code below. I can't seem to put my finger on what I am missing here. Thanks in advance for any help/pointers.

I am using Express.js middleware to render server side like so,

app.use((req, res, next) => {
  const memoryHistory = createHistory(req.originalUrl)
  const preloadedState = {}
  const store = configureStore()
  const history = syncHistoryWithStore(memoryHistory, store)

  match({ history, routes, location: req.originalUrl }, (error, redirectLocation, renderProps) => {
    if (redirectLocation) {
      res.redirect(redirectLocation.pathname + redirectLocation.searc)
    } else if (error) {
      console.error('ROUTER ERROR :', error)
      res.status(500)
    } else if (renderProps){
      loadOnServer(renderProps, store).then(() =>{
        console.info(store)
        const component = (
          <Provider store={store} key="provider">
            <ReduxAsyncConnect {...renderProps} />
          </Provider>
        )
        res.status(200)
        global.navigator = {userAgent: req.headers['user-agent']}

        res.send('<!doctype html>\n' +
                 ReactDOM.renderToString(
                 <HTML
                   component={component}
                   store={store} />)
        )
      })
    } else {
      res.status(404).send('Not Found')
    }
  })

})

I have added reduxAsyncConnect reducer like so

import { reducer as reduxAsyncConnect } from 'redux-async-connect';

const rootReducer = combineReducers({
  // other reducers removed
  reduxAsyncConnect
})

Here's what my routes look like,

const App = ({ store, history }) => (
  <Provider store={store} key="provider">
      <Router history={history}
    render={(props) => <ReduxAsyncConnect {...props} filter={item => !item.deferred} />}>
          {routes}
      </Router>
  </Provider>
)

const store = configureStore()
const history = syncHistoryWithStore(browserHistory, store)

render(
  <App store={store} history={history} />,  document.getElementById('root')
)

Here's the root component

@asyncConnect([{
  promise: () => {
    const promises = [];
    promises.push(loadFlatPages());
    return Promise.all(promises);
  }
}])
@connect(
  state => (state),
  { push,
    loadFlatPages,
  }
)
class Root extends Component {
  constructor(props) {
    super(props)
  }

  componentWillMount() {
    this.props.loadFlatPages()
  }

  render() {

    return (
      <div> {* markup snipped *} </div>
    )
  }
}

export default Root

Here are my action creators. Here I get error UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'dispatch' of undefined

function fetchFlatPages() {
  return {
    [CALL_API]: {
      types: makeActionTriplet(actionTypes.FETCH_FLATPAGES),
      endpoint: 'pages/',
      method: 'get',
    }
  };
}

export function loadFlatPages() {
  return (dispatch, getState) => {
    return dispatch(fetchFlatPages());
  };
}