0

I have a component called PartyDetails, which needs data fetched by an ajax call. I want to show a Loading component while the ajax request is in progress.

The problem is that in order to determine whether the data is loaded or not, I need access to the store. This is how my enhance looks like:

const enhance = compose(
    propSetter,
    lifecycleEnhancer,
    loading,
)

export default enhance(PartyDetails)

where propSetter is:

const propSetter = connect((state) => {
    const { party } = state
    const { dataLoaded } = party
    // for some reason state does not contain match, and I'm resorting to routing
    const { routing: {location: { pathname }}} = state
    const involvedPartyId = pathname.substring(pathname.lastIndexOf('/') + 1)
    return { dataLoaded, involvedPartyId }
}, {loadParty})

and lifecycleEnhancer is:

const lifecycleEnhancer = lifecycle({
    componentDidMount() {
        this.props.loadParty(this.props.involvedPartyId)
    }
})

and loading is ( notice that in this case, dataLoaded comes from the previous connect that has been done in propSetter ):

const loading = branch(
    ({dataLoaded}) => dataLoaded,
    renderComponent(connect(mapStateToProps, mapDispatchToProps)(PartyDetails)),
    renderComponent(Loading)
)

So basically, if the data has been fetched, I am using a 2nd connect to obtain the relevant props for PartyDetails.

I just started learning recompose a few days ago, and I could not find an example that fitted my use case. The above is what I came up with after reading through the docs, and some examples found in other articles.

Is what I'm doing a good way of handling this? Could this be done in a better way, maybe without needing 2 connect calls?

1ven
  • 6,776
  • 1
  • 25
  • 39
Geo
  • 93,257
  • 117
  • 344
  • 520

1 Answers1

0

You could write all your logic for mapping state and dispatch to props in one connect:

export default compose(
  connect(
    state => {
      const { party } = state;
      const { dataLoaded } = party;
      const { routing: { location: { pathname } } } = state;
      const involvedPartyId = pathname.substring(pathname.lastIndexOf("/") + 1);

      // also put here your `mapStateToProps` code

      return { dataLoaded, involvedPartyId };
    },
    {
      loadParty
      // the same here, append `mapDispatchToProps` logic
    }
  ),
  lifecycle({
    componentDidMount() {
      this.props.loadParty(this.props.involvedPartyId);
    }
  }),
  branch(
    ({ dataLoaded }) => dataLoaded,
    renderComponent(PartyDetails),
    renderComponent(Loading)
  )
  // as `branch` is returning HOC, we need to provide empty component to it in
  // order to render whole component
)(createSink());
1ven
  • 6,776
  • 1
  • 25
  • 39
  • The reason I did not have everything in one connect is that data won't exist in state, when the first connect is called. Is there something i'm missing in your example? – Geo Oct 12 '17 at 12:39
  • @Geo it's actually not a problem. In my example, at first render data variable will be undefined(as it not exists at that time) and we will render `Loading` component, where that data is not needed. At the second render, when data will be fetched from server, we will render `PartyDetails` and pass there derived data – 1ven Oct 12 '17 at 13:26