-
-
Notifications
You must be signed in to change notification settings - Fork 630
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Document hydration for XHR-substituted components * Add PR reference to CHANGELOG.md * Add missing route to dummy_no_webpacker
- Loading branch information
1 parent
73cf07e
commit 047f229
Showing
15 changed files
with
223 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<%= react_component('HelloWorld', props: { helloWorldData: { name: 'HelloWorld' } }, | ||
prerender: true, | ||
trace: true, | ||
id: "HelloWorld-react-component-0") %> | ||
<%= react_component('HelloWorldRehydratable', props: { helloWorldData: { name: 'HelloWorldRehydratable' } }, | ||
prerender: true, | ||
trace: true, | ||
id: 'HelloWorldRehydratable-react-component-1') %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
<div id='component-container'> | ||
<%= render partial: 'xhr_refresh_partial' %> | ||
</div> | ||
|
||
<div> | ||
Click to refresh components through XHR (first component event handlers won't work anymore)<br/> | ||
<%= form_tag '/xhr_refresh', method: :get, remote: true, format: :js do %> | ||
<%= submit_tag 'Refresh', id: 'refresh', name: 'refresh' %> | ||
<% end %> | ||
</div> | ||
<hr/> | ||
|
||
<h1>React Rails Client Rehydration</h1> | ||
<p> | ||
This example demonstrates client side manual rehydration after a component replacement through XHR.<br/><br/> | ||
|
||
The "Refresh" button on this page will trigger an asynchronous refresh of component-container content.<br/> | ||
Components will be prerendered by the server and inserted in the DOM (spec/dummy/app/views/pages/xhr_refresh.js.erb)<br/> | ||
No client rehydration will occur, preventing any event handler to be correctly attached<br/><br/> | ||
|
||
Thus, the onChange handler of the HelloWorld component won't trigger whereas the one from HellowWorldRehydratable will, thanks to the "hydrate" javascript event dispacthed from xhr_refresh.js.erb<br /> | ||
</p> | ||
|
||
<hr/> | ||
<h2>Setup</h2> | ||
<ol> | ||
<li> | ||
Create component source: spec/dummy/client/app/components/HellowWorldRehydratable.jsx | ||
</li> | ||
<li> | ||
Expose the HellowWorldRehydratable Component: spec/dummy/client/app/startup/serverRegistration.jsx and spec/dummy/client/app/startup/clientRegistration.jsx | ||
<br/> | ||
<pre style='white-space: pre-wrap; word-break: keep-all;'> | ||
import HellowWorldRehydratable from '../components/HellowWorldRehydratable'; | ||
import ReactOnRails from 'react-on-rails'; | ||
ReactOnRails.register({ HellowWorldRehydratable }); | ||
</pre> | ||
</li> | ||
<li> | ||
Place the component on the view: spec/dummy/app/views/pages/xhr_refresh.html.erb, making sure it has a parent node easily selectable | ||
<br/> | ||
<pre style='white-space: pre-wrap; word-break: keep-all;'> | ||
<div id='my-component-container'> | ||
<%%= react_component("HellowWorldRehydratable", props: { helloWorldData: { name: 'HelloWorld' } }, prerender: true, trace: true, id: "HellowWorldRehydratable-react-component-0") %> | ||
</div> | ||
</pre> | ||
</li> | ||
<li> | ||
Have a remote form allow to get xhr_request.js.erb | ||
<br/> | ||
<pre style='white-space: pre-wrap; word-break: keep-all;'> | ||
<%%= form_tag '/xhr_refresh', method: :get, remote: true, format: :js do %> | ||
<%%= submit_tag 'Refresh' %> | ||
<%% end %> | ||
</pre> | ||
</li> | ||
<li> | ||
In your xhr_request.js.erb, replace your container content and dispatch the 'hydrate' event that will be caught by HellowWorldRehydratable event handler | ||
<br/> | ||
<pre style='white-space: pre-wrap; word-break: keep-all;'> | ||
var container = document.getElementById('component-container'); | ||
<%% new_component = react_component("HellowWorldRehydratable", props: { helloWorldData: { name: 'HelloWorld' } }, prerender: true, trace: true, id: "HellowWorldRehydratable-react-component-0") %> | ||
container.innerHTML = "<%%= escape_javascript(new_component) %>"; | ||
|
||
var event = document.createEvent('Event'); | ||
event.initEvent('hydrate', true, true); | ||
document.dispatchEvent(event); | ||
</pre> | ||
</li> | ||
</ol> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
var container = document.getElementById('component-container'); | ||
container.innerHTML = "<%= escape_javascript(render partial: 'xhr_refresh_partial') %>"; | ||
|
||
var event = document.createEvent('Event'); | ||
event.initEvent('hydrate', true, true); | ||
document.dispatchEvent(event); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
spec/dummy/client/app/components/HelloWorldRehydratable.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import PropTypes from 'prop-types'; | ||
import React from 'react'; | ||
import ReactOnRails from 'react-on-rails'; | ||
import RailsContext from './RailsContext'; | ||
|
||
class HelloWorldRehydratable extends React.Component { | ||
|
||
static propTypes = { | ||
helloWorldData: PropTypes.shape({ | ||
name: PropTypes.string, | ||
}).isRequired, | ||
railsContext: PropTypes.object, | ||
}; | ||
|
||
// Not necessary if we only call super, but we'll need to initialize state, etc. | ||
constructor(props) { | ||
super(props); | ||
this.state = props.helloWorldData; | ||
this.setNameDomRef = this.setNameDomRef.bind(this); | ||
this.forceClientHydration = this.forceClientHydration.bind(this); | ||
this.handleChange = this.handleChange.bind(this); | ||
} | ||
|
||
componentDidMount() { | ||
document.addEventListener('hydrate', this.forceClientHydration); | ||
} | ||
|
||
componentWillUnmount() { | ||
document.removeEventListener('hydrate', this.forceClientHydration); | ||
} | ||
|
||
setNameDomRef(nameDomNode) { | ||
this.nameDomRef = nameDomNode; | ||
} | ||
|
||
forceClientHydration() { | ||
const registeredComponentName = 'HelloWorldRehydratable'; | ||
const { railsContext } = this.props; | ||
|
||
// Target all instances of the component in the DOM | ||
const match = document.querySelectorAll(`[id^=${registeredComponentName}-react-component-]`); | ||
// Not all browsers support forEach on NodeList so we go with a classic for-loop | ||
for (let i = 0; i < match.length; i += 1) { | ||
const component = match[i]; | ||
// Get component specification <script> tag | ||
const componentSpecificationTag = document.querySelector(`script[data-dom-id=${component.id}]`); | ||
// Read props from the component specification tag and merge railsContext | ||
const mergedProps = { ...JSON.parse(componentSpecificationTag.textContent), railsContext }; | ||
// Hydrate | ||
ReactOnRails.render(registeredComponentName, mergedProps, component.id); | ||
} | ||
} | ||
|
||
handleChange() { | ||
const name = this.nameDomRef.value; | ||
this.setState({ name }); | ||
} | ||
|
||
render() { | ||
const { name } = this.state; | ||
const { railsContext } = this.props; | ||
|
||
return ( | ||
<div> | ||
<h3> | ||
Hello, {name}! | ||
</h3> | ||
<p> | ||
Say hello to: | ||
<input | ||
type="text" | ||
ref={this.setNameDomRef} | ||
defaultValue={name} | ||
onChange={this.handleChange} | ||
/> | ||
</p> | ||
{ railsContext && <RailsContext {...{ railsContext }} /> } | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
export default HelloWorldRehydratable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters