How do you mix componentDidMount() with react-redux connect()?

22,371

Solution 1

First, about your edit, that the component at that repo is intended to let you pass functions to the component as props. These will run whenever the React lifecycle methods are run. This is useful for reasons. But those reasons are explained in that repo and not relevant to your question.

Also, you saw this:

const mapDispatchToProps = { getAllTehDatas };

This is ES6 shorthand notation. It just means:

const mapDispatchToProps = { getAllTehDatas: getAllTehDatas };

That is, the name of the property is the same as the name of the variable. Because it's such a common operation, someone clever came up with this shorthand. It can be very confusing if you don't know about it. You should read about es6.

Onward.

There are a number of concepts that are not sharply delineated. Dumb components. Smart components. Container components. Presentational components. Connected components. Pure functional components. It's a lot.

Container components are smart components and presentational components are dumb components.

Sometimes dumb components are a little bit smart. Maybe they have an animation on mouse over. They can even have state.

Pure functional components are just a function. So no methods and no state. That means only props. Since there cannot be state or extra logic, pure functional components are always presentational.

A connected component is a Higher Order Component. This is just a parent component that renders your component as a child. It also does a bit of magic to optimize rendering.

Presentational components should only show stuff but not do stuff. If stuff gets done when you click or type in them, it should be handled by a parent, which can pass handlers to the presentational component. Presentational components are allowed to do some things, but these things must not influence anything outside them.

Container components are supposed to determine what happens. It's where the logic gets crammed into. It's more a React concept than a Redux concept.

Connected components are created with connect. When that's called, we pass some functions. mapStateToProps and mapDispatchToProps.

mapStateToProps can do anything it needs to to generate some props for your component to use. This means that your component then can use these props without having to process the data further. All needed processing can be done in mapStateToProps.

mapDispatchToProps can do anything it needs to do to pass functions that are used directly as event handlers. Often we pass bound action creators, which usually already do everything that the handler needs to do anyway. But we can pass any function and give it any name. So we can call it onClick and pass whatever function we like. You can also create complex action creators with the help of Redux-Thunk to make any event handler into a smart action creator. Thunked action creators have access to dispatch and state.

The above 2 paragraphs outline an interesting point: the HOC created by connect with the help of our mapStateToProps and mapDispatchToProps can easily be made into a full smart component, and the wrapped component can be completely presentational, even if the resulting HOC is to do smart stuff.

Or get this: you can connect an already connected component. Mind blowing, surely. Is it useful to do so? Of course it could be. A component may need some general data from state wherever it's used. You connect it to that data. The resulting component can then be connected to data specific to the place where it's used elsewhere. Common? No. Useful? Yes!

You can also wrap a presentational component in a container component which then gets wrapped with connect. This might be what you're looking for. You can then use componentDidMount to do the fetch in the container component.

But presentational components are only usefully separated from their smarts for 2 reasons:

  • Reusability
  • Testability

If you need neither then you should not separate the two. Why complicate things with no gain?

Also, use componentDidMount, not componentWillMount. The latter also runs server-side, if you use universal components. You don't want your fetch running on the server.

Note that even though a connected component is clearly a wrapper, you should not think of it like that. Think of it as a plugged-in version of the original. The wrapping is just an implementation detail. Also, the wrapper is created and maintained by React-Redux and its bowels are not to be messed around with. This means you cannot change the componentDidMount of the wrapper, or any other part for that matter. And when I say you can't, I mean you totally can but really shouldn't.

To recap, I recommend understanding React, Redux and React-Redux. They go well together, but are not the same thing.

After you grasp the concepts, you just do what you think is best. Make your own rules.

Solution 2

This answer that I made some time ago give you an example of how to properly use connect and make an action call in the component. The only difference is that it's in componentWillMount for me :P

Share:
22,371
Bola Ibrahim
Author by

Bola Ibrahim

Updated on April 07, 2020

Comments

  • Bola Ibrahim
    Bola Ibrahim about 4 years

    This seems like a simple use case but I can't figure it out. I want to display a list of items retrieved from a request to a remote API over HTTP. I would like the screen to show blank initially while the request is taking place, and then get populated with the results when available.

    So I thought I would have two components: the dumb "item list" component, and a wrapper "presentational" component that uh, somehow kicks off the remote request while rendering the dumb component with the empty item list from state.

    I know how to kick off an initial remote request: use componentDidMount().

    and I know how to handle dispatch / connection: I want to use something like:

    const OuterWrapper = connect(
       mapStateToProps,
       mapDispatchToProps
    ) (ItemList)
    

    but how do I get these things to play together? using connect() seems to put things out of reach. I want to asynchronously kick off the API request, and then somehow do a `dispatch(updateItemList(items)) to tell the world that there are new items to be added to the state.

    EDIT:

    I found react-lifecycle-component, but I don't understand the example usage, both before and after. In the longer case why is getAllTehDatas referenced twice? Why is it in mapDispatchToProps plainly without a key:value pair? Why is it needed in there at all if componentDidMount() calls it? And what do you do if that method needs to make use of dispatch()?