3

I'm fairly new to using React/Node/Express, I've chosen kyt as a boilerplate as it seemed like a great choice when looking for a base set of files to work from. I'm using the default React starter kyt.

My job is to take a bunch of JSON that's dumped from a CMS, and turn it into a React site.

For this to work, I need to be able to populate the 'routes' with data from this JSON file. I've used the code posted below, and this works great. The problem here though, is that my 'import' of the JSON means the data gets compiled into my bundle (by webpack) - which is fine, until the CMS updates the JSON file, at which point the bundle.js doesn't update, rendering it out-of-date (unless I wrote some code to recompile the bundle every time the CMS updates, which I don't like the sound of).

What I need is for the code to load the JSON file at runtime, rather than when the compiling happens.

Can anyone point me in a direction here, please? I've tried a bunch of things, including AJAX/axios requests - but nothing seems to work. I read that Webpack's 'System.import' feature could help me, which I've tried - but that also bundles my data into the compiled bundle.js.

import React from 'react';
import Route from 'react-router/lib/Route';
import IndexRoute from 'react-router/lib/IndexRoute';

import App from '../components/App.js';
import Home from '../components/Home.js';
import Standard from '../components/Standard.js';
import Listing from '../components/Listing.js';
import FourOhFour from '../components/FourOhFour.js';

// THIS IS THE PROBLEM - I don't want this to be bundled
import Model from '../app-json/model.json';

const componentRegistry = {
    "Home": Home,
    "Standard": Standard,
    "Listing": Listing,
    "FourOhFour": FourOhFour
}


function buildDynamicRoutes(config){
    var routeJSX = [];
        Object.keys(Model.posts).map((key) => {
            var thisComponent = '';
            if(Model.posts[key].template === 'page-listings.php'){
                thisComponent = 'Listing';
            } else if(Model.posts[key].template === ''){
                thisComponent = 'Standard';
            }
            routeJSX.push(
                <Route path={Model.posts[key].route} components={componentRegistry[thisComponent]} key={key} />
            );
        });
        return routeJSX; 
}

const routes = (
    <Route path="/" component={App}>
        <IndexRoute component={Home} />
        { buildDynamicRoutes() }
        <Route path="*" component={FourOhFour}/>
    </Route>
);

export default routes;
rorymorris89
  • 1,144
  • 7
  • 14

1 Answers1

0

Update:

Doing the same thing, but server side is just as easy. You can choose to either host it remotely like I said below and use a library like request or even the built in Node http library to get he remote file contents.

Alternatively, when you dump the CMS file, instead of putting the file on some random remote file store, you could put it on the server doing the rendering and use Node's fs library to read the file from disk.

In both cases, you would then have to parse the JSON data and feed it into your component.


Since you are working with front-end code, you've got two choices:

  1. Load the JSON when the React code is compiled by Webpack. This is what is happening now.

  2. Load the JSON when the React code executes on the browser. This could be done by hosting your JSON export on some static file storage (Like S3, but there are many alternatives) and using AJAX to load and parse the JSON file when the component mounts.

Here's another answer which explains how to do this.

https://stackoverflow.com/a/14388512/4697675

You'll probably want to load the JSON file into your component's state and then render with that. That way, before the AJAX call is complete, you can render without the data.

Community
  • 1
  • 1
Alex Anderson
  • 660
  • 6
  • 16
  • Hi, thanks for the answer. Loading the data into React on the client-side is not an issue, this is related to loading it on the server-side when Express/Node executes. Server-side rendering is integral for my project so I cannot accept this answer. – rorymorris89 Feb 06 '17 at 11:45
  • @rorymorris89 your question is not having details about isomorphic rendering. Could you modify it to include that, like how you have connected with the CMS and get the first JSON and later updates? Alternatively, is this is OSS, the github link would help. – hazardous Feb 07 '17 at 07:02
  • @Alex Anderson thank you for updating your answer. Using `request` or `http` or `axios` does not work - as they are asynchronous, the rest of the file executes, including the `export default routes` before the requests are finished. I could use a `sync-request`, but that is bad (apparently). I've also tried using `fs` as you mention - but this also, annoyingly, gets bundled into the `bundle.js` by Webpack (the same as how the original `import` works). – rorymorris89 Feb 08 '17 at 15:42
  • @rorymorris89 Give this a go: https://gist.github.com/TylerK/bf8551648ff49d74bf63124b2c9a63d9 – Alex Anderson Feb 09 '17 at 17:57
  • Hi @AlexAnderson - thanks for that, that would be a fine solution *if* my app didn't *need* to have dynamic routes (that is using hardcoded routes i.e. pages/work and pages/about) – rorymorris89 Feb 13 '17 at 11:20