Coder Social home page Coder Social logo

mitranim / react-ideal Goto Github PK

View Code? Open in Web Editor NEW
2.0 3.0 0.0 20 KB

Run isomorphic React apps on the server without a DOM polyfill

JavaScript 97.40% Shell 2.60%
react isomorphic renderer nodejs server dom-polyfill react-server react-server-render ssr

react-ideal's Introduction

Overview

react-ideal allows you to run React apps on the server without a DOM polyfill. It allows the view tree to update over time, so you can wait until it's ready before rendering static markup.

The view tree exists as an abstract, ideal version of itself, updating over time as you'd expect in a client-side app. This allows you to implement true isomorphic rendering while maintaining the client-side model of data fetching, where each view loads its data independently.

In technical terms, this is an alternate renderer for React that provides crucial functionality omitted by react-dom/server.

Requires React version 16+.

TOC

Renderer Comparison

react-dom → browser, live/async

react-native → mobile, live/async

react-dom/server → Node, sync

react-ideal → Node, live/async → elements → react-dom/server → markup

Key differences with react-dom/server:

  • Creates a live component tree that updates over time
  • Properly handles unmounting
  • Doesn't render to string; you still need react-dom/server for that

Usage

Install from NPM:

npm install --exact react-ideal

Make sure you have React 16+:

npm install --exact react@16 react-dom@16

Use on server:

const {createElement} = require('react')
const {createContainer, renderToContainer, unmountAtContainer, containerToElements} = require('react-ideal')
const {renderToStaticMarkup} = require('react-dom/server')

function myRequestHandler(req, res, next) {
  const container = createContainer()
  const rootElem = createElement(MyReactComponent)
  renderToContainer(container, rootElem)

  somehowWaitUntilViewsAreReady(container, () => {
    const [element] = containerToElements(container)
    const markup = `<!doctype html>${renderToStaticMarkup(element)}`
    req.end(markup)
    unmountAtContainer(container)
  })
}

Gotchas

Async

Unlike react-dom/server, the initial rendering is asynchronous. If you're whipping up a small demo where rendering is done in one pass, make sure to wait for that pass to finish:

const container = createContainer()
const rootElem = createElement(MyReactComponent)
renderToContainer(container, rootElem, () => {
  const [element] = containerToElements(container)
  const markup = `<!doctype html>${renderToStaticMarkup(element)}`
  unmountAtContainer(container)
})

Readiness

To take advantage of react-ideal, you need the view components to signal their readiness status. For now, this is out of scope for react-ideal, but is trivial to implement. Here's a recipe:

const {createElement: E} = require('react')
const {createContainer, renderToContainer, unmountAtContainer, containerToElements} = require('react-ideal')
const {renderToStaticMarkup} = require('react-dom/server')
const PropTypes = require('prop-types')
const {Future} = require('posterus')

async function renderAsync() {
  const container = createContainer()
  const readiness = new Readiness()
  const rootElem = E(ReadinessContext, {readiness}, E(AsyncView))
  renderToContainer(container, rootElem)

  try {
    await readiness.future
    const [element] = containerToElements(container)
    const markup = `<!doctype html>${renderToStaticMarkup(element)}`
    return markup
  }
  finally {
    unmountAtContainer(container)
  }
}

class AsyncView extends PureComponent {
  constructor() {
    super(...arguments)
    this.state = {greeting: ''}
  }

  componentWillMount() {
    this.context.readiness.unready(this)

    setTimeout(() => {
      this.setState({greeting: 'Hello world!'})
      this.context.readiness.ready(this)
    }, 50)
  }

  render() {
    const {state: {greeting}} = this
    if (!greeting) return null
    return E('span', {className: 'row-center-center'}, greeting)
  }
}

AsyncView.contextTypes = {readiness: PropTypes.object}

class ReadinessContext extends PureComponent {
  getChildContext() {
    return {readiness: this.props.readiness}
  }
  render() {
    return this.props.children
  }
}

ReadinessContext.propTypes = {readiness: PropTypes.object}
ReadinessContext.childContextTypes = {readiness: PropTypes.object}

class Readiness {
  constructor() {
    this.future = new Future()
    this.notReady = new Set()
  }

  isFullyReady() {
    return !this.notReady.size
  }

  ready(component) {
    this.notReady.delete(component)
    if (this.isFullyReady()) this.future.arrive()
  }

  unready(component) {
    this.notReady.add(component)
  }
}

react-ideal's People

Contributors

mitranim avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.