I spend a lot of time thinking about how to best structure things as cleanly as possible in React. Lately I've been getting hung up on whether React containers should do nothing but connect to Redux (or other data - a la Meteor) and render/return a single component, or if containers should also be in charge of event-handling as well. So for example, it's a toss-up between these two models:
// ThingContainer.js
import Thing from '../components/Thing';
export default someHigherOrderFunc(/* map state/data to props */)(Thing)
// Thing.js
export default class Thing extends Component {
handleClick() { /* ... */ }
handleMouseEnter() { /* ... */ }
render() {
// Other components rendered here, both container or presentational
}
}
// ThingContainer.js
class ThingContainer extends Component {
handleClick() { /* ... */ }
handleMouseEnter() { /* ... */ }
render() {
// Now Thing can be stateless
return <Thing
onClick={this.handleClick}
onMouseEnter={this.handleMouseEnter}
/>
}
}
export default someHigherOrderFunc()(ThingContainer)
It almost feels like in model 1, Thing
becomes its own container in a sense, which I'm not sure I like. Model 2 feels more natural, as ThingContainer
is charged with not just dealing with data and Redux, but also handling events, firing off Ajax requests in componentDidMount
, etc. With the first model, if I wanted an Ajax request to be invoked in componentDidMount
, it would have to go in Thing
which doesn't seem right.
I'm wondering if there are any particular advantages or pitfalls to either of these approaches, or if it just comes down to style/preference.
In this method, we initiate the AJAX request using XMLHttpRequest . We use the GET method and https://programming-quotes-api.herokuapp.com/quotes/page/1 as the endpoint which returns a JSON output of first page quotes. readystatechange handler is called when the readyState of the request changes.
Where in the component lifecycle should I make an AJAX call? You should populate data with AJAX calls in the componentDidMount lifecycle method. This is so you can use setState to update your component when the data is retrieved.
Here's an example below: import React from “react” export const exampleComponent = ({ children }) => { const open = () => { alert("You clicked this container component") } return ( <div onClick={open}> {children} </div> ); };
There is nothing inherently wrong with doing AJAX inside the “presentational-ish” Thing
when it’s only a couple of methods, and this component is never used in different scenarios anyway. Don’t split behavior from presentation before you’re sure how the behavior changes in different contexts.
That you have this dilemma means your component doesn’t need to be reused yet. In this case it doesn’t matter how you split it. Both ways work fine so I’d go for the simpler one (model 1).
Later you may realize that you want to reuse the same look-n-feel but trigger different AJAX calls, or compute the props differently. At this point you may want to remove the event handling from Thing
and create several different ThingContainer
s, each handling events and computing props a little bit differently. This is when separating presentation and behavior becomes useful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With