preact-cli icon indicating copy to clipboard operation
preact-cli copied to clipboard

Serialize and hydrate data from prerender-urls on the client.

Open developit opened this issue 6 years ago • 4 comments

It would be good if we could detect that prerender-urls has passed more than { url, title } as the data for a given route, and serialize that into the HTML:

<script type="text/props" id="appprops">
  { "url": "/profile/john", "profile": { "name": "John Doe" } }
</script>

Then we can pass these to <App /> when booting on the client.

developit avatar May 04 '19 11:05 developit

Just to add on to this, it would be great to see a canonical and documented way to use serialized and hydrated data inside component templates between npm start (dev) and npm run build --prerender-urls (prod build). Currently the only way I've found is to save the data to state inside the application component and then have some verbose templating syntax for fallthrough app.js

let INIT = {};
if (typeof document!=='undefined') {
  try {
    INIT = JSON.parse(document.getElementById('app_props').textContent) || {};
    console.log(INIT, 'whyy tho')
  } catch (e) {console.error(e)}
}

export default class App extends Component {
  constructor(props) {
    super(props);
    this.init = INIT || props;
    console.log(this.init);
  }

  /** Gets fired when the route changes.
   *  @param {Object} event    "change" event from [preact-router](http://git.io/preact-router)
   *  @param {string} event.url  The newly routed URL
   */
  handleRoute = e => {
    this.currentUrl = e.url;
    this.fetchOrSetData();
  };

  fetchOrSetData() {
    if (this.currentUrl === this.init.url && this.init.data) {
      this.setState({data: this.init.data});
    }
    else {
      fetch('http://www.filltext.com?rows=10&f={firstName}').then(res => {
        const json = res.json();
        return json;
      }).then(data => {
        console.log('data fetced', data[0].f);
        return this.setState({data: {name: data[0].f}});
      });
    }
  }

  render() {
    return (
        <div id="app">
          {typeof window==='undefined' &&
            <script type="text/props" id="app_props" dangerouslySetInnerHTML={{__html: JSON.stringify({ url: this.props.url, data: this.props.data })}}></script>
          }
          <h1>Hello Yes: {this.props.data && this.props.data.name || this.state && this.state.data && this.state.data.name}</h1>
          <Router onChange={this.handleRoute}>
            <Redirect path="/" to="/menu"/>
            <Menu path="/menu" url={this.currentUrl}/>
            <Work path="/work" url={this.currentUrl}/>
          </Router>
        </div>
    );
  }
}

Imagine that every single piece of text content on a site was authored in a cms: Every template binding would need something along the lines of this:

{this.props.data && this.props.data.name || this.state && this.state.data && this.state.data.name}

@developit had an idea to monkey patch fetch

This could be an implementation but still not sure on how to do this at scale of the entire site's content?

matthewharwood avatar May 05 '19 18:05 matthewharwood

Nice to see this on the table. I'm currently using https://github.com/nozzle/react-static and wanted to switch to preact, but I really need this feature.

For example, I have a lot of pages that all share the same component, but with different data. The tricky is also where the url is more flexible than would be convenient in preact.

Take these routes:

  • /product/doll/white
  • /product/doll/black
  • /product/puppet/white/large
  • /product/puppet/white/small
  • /product/puppet/black/large
  • /product/puppet/black/small

All these routes would use the Product component, and the amount of sections in the path is completely arbitrary. This makes it rather annoying to configure a Router in code and it would be nice to let the Router generate all these routes based on said data.

StephanBijzitter avatar May 25 '19 20:05 StephanBijzitter

Yeah for me that's the thing we have to figure out, parity between dev and build for this data

Also it wouldn't get fetched after route changes currently

It's initial data to hydrate from, but nothing more

ForsakenHarmony avatar May 26 '19 22:05 ForsakenHarmony

We don't want to write these out as files, do we? ("static API routes"?)

build/product/doll/white
build/__preact_data/product/doll/white.json

developit avatar May 28 '19 17:05 developit