We have a legacy system where we load parts of a form asynchronously. Now we want to replace parts of that form with react components. However, if I use react_component in a template that's loaded via an xhr request, it doesn't activate. If I use prerender: true the component renders, but it isn't rehydrated.
Is there anything I can call to activate the component from the template?
@thomassnielsen Try out: https://github.com/shakacode/react_on_rails/blob/master/node_package/src/ReactOnRails.js#L83
If you don't want to reload everything, see what that function calls. Feel free to ask me to re-open this.
Hi,
I may have missed something but I couldn’t find a way to use ClientStartup.render without modifying the node module, and neither could I re-render all of my components, so I came with another solution:
In a component:
componentDidMount () {
// If several Ajax calls can lead to different components needing an hydration cycle, you can set a more specific event name, e.g. 'hydratemycomponent’.
document.addEventListener('hydrate', this.forceClientHydration)
}
componentWillUnmount () {
document.removeEventListener('hydrate', this.forceClientHydration)
}
forceClientHydration = () => {
const registeredComponentName = 'MyRegisteredComponent' // from startup/registration.jsx
// I use current (synchronous) railsContext, mind using an updated version if your ajax call returns a new one
const { railsContext } = this.props
// Target all instances of the component
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) {
const component = match[i]
// Get <script> tag, which is the previous element sibling (this avoids Gecko empty "Text" nodes)
const componentScript = component.previousElementSibling
// Read props from the script tag and merge railsContext
const mergedProps = {...JSON.parse(componentScript.textContent), railsContext}
// Hydrate, you'll have to import ReactOnRails from 'react-on-rails'
ReactOnRails.render(registeredComponentName, mergedProps, component.id)
}
}
To trigger it from your ajax call callback:
var event = document.createEvent('Event')
event.initEvent('hydrate', true, true)
document.dispatchEvent(event)
Also, if you use Redux, make sure the redux_store from your controller is also called when serving async requests, I wasted some time on this one.
@hchevalier if you think this is generally useful, please create a very simple demonstration of why in the sample app in the /spec/dummy of this repo. Throw some docs, a changelog entry, and a test, and I'll merge it!
@hchevalier Please email me at [email protected] to get an invite to our Slack channel.
Most helpful comment
@thomassnielsen Try out: https://github.com/shakacode/react_on_rails/blob/master/node_package/src/ReactOnRails.js#L83
If you don't want to reload everything, see what that function calls. Feel free to ask me to re-open this.