Skip to content

Commit

Permalink
Merge pull request #691 from Financial-Times/hydration-props
Browse files Browse the repository at this point in the history
  • Loading branch information
apaleslimghost authored Jan 24, 2023
2 parents 7ce5df3 + 62707ae commit f360dce
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 5 deletions.
3 changes: 2 additions & 1 deletion components/x-increment/src/Increment.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ const withIncrementActions = withActions(({ timeout }) => ({
}
}))

const BaseIncrement = ({ count, actions: { increment }, isLoading }) => (
const BaseIncrement = ({ count, customSlot, actions: { increment }, isLoading }) => (
<div>
<span>{count}</span>
<button onClick={() => increment()} disabled={isLoading}>
{customSlot}
{isLoading ? 'Loading...' : 'Increment'}
</button>
</div>
Expand Down
20 changes: 19 additions & 1 deletion components/x-interaction/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,25 @@ A full example of client-side code for hydrating components:
import { hydrate } from '@financial-times/x-interaction';
import '@financial-times/x-increment'; // bundle x-increment and register it with x-interaction

document.addEventListener('DOMContentLoaded', hydrate);
document.addEventListener('DOMContentLoaded', () => hydrate());
```

If the underlying component requires properties that can't be serialised, such as functions or other components, you can pass these as an argument to `hydrate`, as long as they can be the same value of every instance of that component. The argument to `hydrate` is an object mapping `x-interaction`'s internal name for a component to an object containing additional properties to pass to every instaance of that component. You can access a component's internal name by calling `getComponentName`.

For instance, `x-interaction` supports a `customSlot` property for rendering a React element into the button, but that can't be serialised. To render that on the client, we can pass it in as an additional hydration property:

```js
import { hydrate, getComponentName } from '@financial-times/x-interaction';
import Increment from '@financial-times/x-increment';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

document.addEventListener('DOMContentLoaded', () => {
hydrate({
[getComponentName(Increment)]: {
customSlot: <FontAwesomeIcon icon='plus' />
}
})
});
```

### Triggering actions externally
Expand Down
8 changes: 6 additions & 2 deletions components/x-interaction/src/Hydrate.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class HydrationWrapper extends Component {
}
}

export function hydrate() {
export function hydrate(additionalProps = {}) {
if (typeof window === 'undefined') {
throw new Error('x-interaction hydrate should only be called in the browser')
}
Expand All @@ -51,6 +51,7 @@ export function hydrate() {
}

const Component = getComponentByName(component)
const additionalComponentProps = additionalProps[component] || {}

if (!Component) {
throw new Error(
Expand All @@ -66,10 +67,13 @@ export function hydrate() {
<HydrationWrapper
{...{
Component,
props,
id,
wrapper
}}
props={{
...props,
...additionalComponentProps
}}
/>,
wrapper
)
Expand Down
2 changes: 1 addition & 1 deletion components/x-interaction/src/Interaction.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,4 @@ export const withActions = (getActions, getDefaultState = {}) => (Component) =>
export { hydrate } from './Hydrate'
export { HydrationData } from './HydrationData'
export { Serialiser } from './concerns/serialiser'
export { registerComponent } from './concerns/register-component'
export { registerComponent, getComponentName } from './concerns/register-component'

0 comments on commit f360dce

Please sign in to comment.