Bind data requests from your API to your React Components Tl;dr In React applications, a common requirement is to render data which is dynamically loaded from an API into a component, on both server and client renders. is a library that lets you declaratively bind custom data loading logic to your components, and then automatically fires the data loading when the component renders on both server and client. react-frontload It integrates easily into your existing React stack, and . requires no changes to your existing data API : github https://github.com/davnicwil/react-frontload : npm package react-frontload Please read on to explore the problem, how solves it, and see some code examples. react-frontload A Typical Use Case In the most straightforward use case, you have a view component which displays some dynamic data for some URL, which contains the parameters required to load the data from your API. example www.myreactapp.co/profiles/**davnicwil** shows the profile view for user davnicwil To load davnicwil’s profile data, a GET request is made to api.myreactapp.co/users/**davnicwil** Everything up to and including the initial render of the component is synchronous. The data request, however, is asynchronous. The component rendering lifecycle is synchronous by design. There is no way, once component rendering has begun, to wait until the data request has resolved before continuing. The asynchronous data request and the component render must be decoupled. React This decoupling can be achieved in a straightforward way by passing required data to a view component via props, and rendering a loader if these props are empty. example const ProfileView = (props) => (props.profile? <div>{props.profile.fullName}'s profile</div>: <div>loading..</div>) The Problem The important question is: when is the data request fired? , it doesn’t matter when the data request is fired. It can happen before or after the initial render of the component. All that matters is that when the request resolves, the results are fed into the component’s props. React will then re-render the component, and you’re done. On the client, components can be thought of as long-lived state machines, sitting there indefinitely waiting to re-render whenever their props are updated. On the client example class ProfileContainer extends React.Component { componentDidMount () {// asynchronously load the profile// into this.props.boundProfile// via your state management solution of choice,getProfileAsync(this.props.username)} render () {// this.props.boundProfile will at some point// contain the loaded profile. For the initial// render it will be undefinedreturn (<ProfileView profile={this.props.boundProfile} />)} } , order matters. That’s because for each individual page request, our same view component is created, rendered exactly once with whatever initial props you provide, and then discarded. Any data passed via props must be loaded before this single render occurs. On the server the component is better thought of as a pure function than a long-lived state machine. On the server example const handleServerPageRequest = async (req, res) => {// data request must happen first.// wait until it's done before continuingconst profile = await getProfileAync(req.body.username) // render component passing loaded data via props// note that this is a plain synchronous function callconst markup = ReactDOM.renderToString(<ProfileContainer profile={profile} />) // send the rendered markup in the responseres.send(markup)} Both patterns for client and server are straightforward, but require different wiring to get the request and the subsequent component (re-)render to fire. The high-level intent in both cases is the same: to specify that some data dependencies will be loaded into props for the component to render — synchronously on the server and asynchronously on the client. There is another important feature that the patterns above don’t accommodate. When server-rendering a component with data, we probably don’t want to re-load the data as soon as the component renders on the client. We need the component to know that it has been server rendered, and then only reload the data on updates to the parameters which are used for the data request. For example, if the username in the URL changes on an in-app navigation, and the component needs to load and render a different user’s profile, when the username prop updates. Of course we can implement this feature on top of the patterns above, but it involves a lot of small details that are easy to get wrong, even with the help of a state management solution. After implementing the wiring code for these patterns time and again for my components, I eventually found myself really needing an abstraction for it. The wiring code is not all that complex by itself, but there are lots of details and so the usual DRY rule applies — it just stops being manageable once you need to repeat it for more than a few components. A Solution After a few attempts at writing a library using various patterns and falling into pitfalls as I went along, I eventually uncovered my desired feature set: A component’s data-loading logic should just be a regular JS function, returning a Promise for async. The function should be co-located with the component. Declarative, co-located, plain JS data-loading logic: The data-loading function should interface with the rest of the application only via component props, so it can play nicely with arbitrary libraries in the rest of the stack without any implicit dependencies or integrations beyond React itself. Idiomatic React: : A component’s data-loading function should work the same regardless of where the component is placed in the app’s component tree. Component encapsulation & independence : It should be possible to fine-tune when the data loading function runs so that special cases can be handled. The defaults should set up the component for the most common use-case. Configurable component data-loading behaviour I implemented those features into a library: Here’s the result, with the same example as before, using react-frontload. react-frontload. import { } from 'react-frontload' frontloadConnect // assuming here that getProfileAsync returns a Promise that// resolves when the profile is loaded into props.boundProfileconst frontload = (props) => (getProfileAsync(props.username)) // all available options, set to the default valuesconst options = {noServerRender: false,onMount: true,onUpdate: true} // just decorate the same underlying component from earlierconst ProfileView = (frontload, options)((props) => (props.profile? <div>{props.profile.fullName}'s profile</div>: <div>loading..</div>)) frontloadConnect With just those few lines of code, the profile data is loaded in and rendered on both client and server, and we’ll also get the nice feature discussed earlier where the request is not unecessarily re-fired on the first client render immediately after a server render. All that remains is two tiny changes, to make your application react-frontload aware. 1. Wrap your application with the provider Frontload // beforeconst Application = () => (<div>{/* application content here */}</div>) // after: react-frontload awareconst Application = () => (<Frontload><div>{/* application content here */}</div></Frontload>) 2. Use the special react-frontload function on the server serverRender // beforeconst store = initStore(req)const markup = ReactDOM.renderToString(<Application store={store} />)res.send(markup) // after: react-frontload awareimport { } from 'react-frontload' serverRender ... const store = initStore(req)// encapsulate exactly the same render code as above in a// function and pass it const markup = serverRender(() => (ReactDOM.renderToString(<Application store={store} />)))res.send(markup) serverRender And that’s all that’s required. It’s ready to use. Just to comment on the code missing from the example — i.e. binding the asynchronously loaded profile to props.boundProfile, and the username from the URL to props — I left those details out purposefully, as established libraries and patterns exist and react-frontload has no opinion about which you use. This works because the component’s frontload function interfaces with the component only via props. This was one of the design goals, and hopefully it’s clear how simple it makes it to use react-frontload in any existing stack. You make these bindings to your component props in the same way you always do, and then you can access them in the component’s frontload function. You don’t have to do anything extra to get the bindings to work. The react-frontload API **frontloadConnect(frontload, [options])(Component)** is the bridge between the library, and the Component you want to load data into. frontloadConnect Let’s go through the frontload and options parameters. **frontload(props)** A function which is called with the props, and returns a Promise which must resolve when all the required data-loading is complete. Component The full power and flexibility of the Promise API is therefore available to encapsulate the asynchronosity of the data-loading behaviour into a single returned Promise — that means a single request is fine, but equally if multiple requests are required they can just be chained with (if order matters) or parallelised with (if they are independent). .then Promise.all **[options]** The object provides three configurations that specify when exactly the function should fire on both client and server. If any particular configuration is left undefined, it takes its default value. Likewise, if the entire object is left undefined, all three configurations take their default values. options frontload options 1 **noServerRender** (boolean) [default false] When , the ’s function will run on every server render. In the example, this ensures the component server renders with the expected profile, rather than the ‘loading..’ placeholder. false Component frontload When , the ’s function will not run on server render. In the example, the component would be server rendered with the ‘loading..’ placeholder, since no profile is loaded. true Component frontload Importantly, when this is it also turns off the feature that prevents the component from loading data on mount after a server render. Assuming the option to load data on mount (discussed below) is set, the frontload function will fire on first mount after server render, since react-frontload knows that the data was not loaded on the server and the ‘loading..’ placeholder has to be replaced with the loaded in profile. true : if you need to turn off server rendering for an entire application, instead of setting this configuration true on every individual component, can instead be set as a prop on the application’s provider like this: Note noServerRender Frontload <Frontload ><div>{/* app code */}</div></Frontload> noServerRender 2 **onMount** (boolean) [default true] This options toggles whether or not the function should fire when the mounts on the client. Again, this only skips when the was server rendered immediately before hand— see above for more details. frontload Component Component The default is and 99% of the time this is what it should be. After all, in almost all cases you want to load the data and render it when the is first displayed. It is provided as an option to accommodate edge cases, however. true Component 3 **onUpdate** (boolean) [default true] Very similar to , this options toggles whether or not the function should fire when the ’s props update on the client. onMount frontload Component The default is and again, for a well designed application component tree with proper restriction of unnecessary updates when props do not change (via ) it is likely that this is fine. true shouldComponentUpdate For edge cases, or to remove the need to change component trees that trigger spurious updates where this is infeasible, it can be set to . false Note that there is a common case where some but not all props should trigger the function. In our example, we’d always want to fire it when updates, but what if there was another prop, , that could also update but which would not require the profile to be reloaded. frontload username textColor I thought about making this configurable via another field, for example by providing prop names that should trigger the function to fire when they update. But I realised that this strayed into DSL territory, with all the loss of power and maintainability issues that brings, and in fact there is already a mechanism for dealing with this with the full power of JS — recall that the function itself receives the props. Therefore, we can make any arbitrarily complex decisions about whether to actually fire any expensive requests on update in the function itself. options frontload frontload Component Component frontload — **frontloadServerRender**(renderFunction) The function can be thought of as a decoration of your existing React server render logic, which you have to encapsulate in a which outputs server-rendered React markup. Usually, will be a simple wrapper over a call. frontloadServerRender renderFunction renderFunction ReactDOM.renderToString The output of frontloadServerRender is the same markup that renderFunction produces, which can be returned in the response to the client in the usual way. It is nothing more than a proxy for this function, and exists only to ‘inject’ the plumbing code required to do synchronous loading of all the frontload functions in the application prior to final rendering. How does it work? (coming soon) In a post I’ll explain how is implemented. For now, if you’re curious please read the source, which I’ve tried to write as clearly as possible, and is itself commented with some implementation notes. future react-frontload I hope you found this post interesting. I developed to tidy up and improve the code in my own applications, and also as a learning experience after thinking about this problem for a while and trying and failing multiple times to come up with a nice way to solve it. react-frontload I put the source and npm package out there in case this solution could be useful for anyone else in the React community. It has decent test coverage, and I’ve been using it for a while in production on my side project where it’s being performing without issues. https://postbelt.com However, it’s very much written to serve my particular use cases, and it’s quite possible that there are bugs / edge cases that I haven’t caught simply because I’ve not needed to use them yet. I’m more than happy to answer any questions and review PRs on the github repo if that’s the case! Thanks for taking the time to read this post. is how hackers start their afternoons. We’re a part of the family. We are now and happy to opportunities. Hacker Noon @AMI accepting submissions discuss advertising & sponsorship To learn more, , , or simply, read our about page like/message us on Facebook tweet/DM @HackerNoon. If you enjoyed this story, we recommend reading our and . Until next time, don’t take the realities of the world for granted! latest tech stories trending tech stories