reactjs / rfcs

RFCs for changes to React
MIT License
5.52k stars 558 forks source link

[Proposal] + ReactDOM.hydrateElement #94

Closed English3000 closed 3 years ago

English3000 commented 5 years ago

A colleague at work recently turned me onto Vue. So I read "The Majesty of Vue 2".

In it, there is a project where you use Vue for a search bar and results.

After learning Vue, I looked to see if React had any functionality like it. The closest I could find is React Hooks.

Below are pictures of a search bar with results (and their respective code bases) rendered with React and with Vue.

react hooks vue rendered

react hooks vs vue

In a nutshell, the one use case where Vue beats React is SSR because in order to make that work in React, one needs to setup a Node server.

What I am proposing is a Vue-inspired work around. react-dom already provides the functions render + hydrate, which replace a DOM node with one generated by React.createElement

What if instead of replacing an entire node, you could simply inject JavaScript into it?

ReactDOM.hydrateElement(propertiesObject, domNode)

So, for example, instead of:

<div id="react-storyboard"></div>

and

render( <Storyboard users={reactUsers}/>, document.getElementById("react-storyboard") )

I could do

<input id="search-bar"
       type="text"
       placeholder="Search for stories... with React Hooks!"
       value="">

<ul id="search-results">
  <!-- using real data, the server-side could display data here -->
</ul>
let users = API.getUsers(),
    [query, setQuery] = useState(""),
    [data,  setData]  = useState(users)

function handleChange(event){
  setQuery(event.target.value)

  let newData = {}
  for (const key in users) {
    newData[key] = users[key].filter(
                     story => story.includes(event.target.value)
                   )
  }

  setData(newData)
}

const SearchResults = ({data}) =>
  <ul>{Object.entries(data).map(([name, stories]) =>
    stories.map((story, index) =>
      <li key={index}>
        {name} posted "{story}"
      </li>
    )
  )}</ul>

ReactDOM.hydrateElement({value: query, onChange: handleChange}, document.getElementById("search-bar"))
ReactDOM.render(<SearchResults data={data}/>, document.getElementById("search-results"))

In this way, I no longer have to duplicate an <input> and include an extra <div> to get SSR.

cc: @gaearon

English3000 commented 5 years ago

@sophiebits, WDYT?

English3000 commented 5 years ago

a la morphdom but with a cleaner React API.

gaearon commented 3 years ago

Hi, thanks for your suggestion. RFCs should be submitted as pull requests, not issues. I will close this issue but feel free to resubmit in the PR format.