react-freud v3.0.0
Freud
It gets in your head
Freud is an head manager for React applications. It supports server-rendering and thus is compatible with your SPAs or any other amenity.
Freud is inspired by react-helmet, but it's a far simpler implementation (which is largely possible thanks to the awesome react-side-effect).
Example
import React from 'react';
import Freud form 'freud';
/* the tag renders as null and sets the provided properties */
/* properties on tags which appear later/deeper in the render tree override previous tags */
const OEdipus = () =>
<div>
<Freud title="I've got a problem" />
<Freud title="Maybe two" />
{"Mom is best ❤️"}
</div>;
const Mother = () =>
<div>
<Freud
titleTemplate="OEdipus news | %s"
links={[{ rel: 'stylesheet', href: 'thebes.css' }]}
/>
</div>;
ReactDOM.render(
<main>
<Freud
links={[{ rel: 'stylesheet', href: 'vienna.css' }]}
scripts={[{ src: 'dreams.js', async: true }]}
/>
<Mother />
<OEdipus />
<Freud syncHere={true} />
</main>
);Usage
Install it the npm-way:
npm install react-freud --saveYou'll need also react as peerDependencies.
<Freud prop=value />
It's just a normal component which renders to null but does some magic at render time. The fact it renders to null means it swallows all its children so don't use it as a wrapper component.
title: sets the title of the page.defaultTitle: if notitleis set, this becomes the title, otherwise it's overridden (low-precedencetitle).titleTemplate: a format string where%sgets replaced by thetitle(in the example above, the page title will be OEdipus news | Maybe two).links: an array of PJOs whom attributes will be set on<link>tags. Arrays are not overridden but merged, for instance in the above example Freud will addvienna.cssandthebes.css(preserves order). However, if you add two identical objects (identical == deeply equal), Freud will only load one.scripts: same semantics oflinks, but creates<script>tags.metas: same semantics oflinks, but creates<meta>tags.
To do the actual modifications to head there are two options:
- Use the
syncHereattribute on aFreudtag (see example). When this component is rendered, theheadstate will be synced with all the options set until now. So use this only if you want to force some rendering or you are 100% sure this is the lastFreudtag that is rendered - Use the
syncmethod ofFreud, which does the same thing. - Use withFreudSync HoC component which automatically calls
Freud.sync()whenever its children change. This is the most effective way, especially if you're using routing: just wrap your top components with it:
import { withFreudSync } from 'react-freud';
<Router>
<Route component={withFreudSync(MyComponent)} path="/foo" />
<Route component={withFreudSync(MyOtherComponent)} path="/bar" />
</Router>Why all this trouble?
Because of the way react-side-effect works, Freud cannot know if the properties encountered until now are complete or something is missing. So if I sync head every time a Freud tag is rendered, I could unmount some tag which is required by a Freud tag deeper in the render tree.
In particular, by doing this Freud works fine with server-side rendering.
On the serve, use the amazing rewind() function to get the tags to put in your head.
import Freud from 'freud';
const html = ReactDOM.renderToStaticMarkup(<MyAppContainer />);
const { title, scripts, links, metas } = Freud.rewind();
sendResponseBody(
`<!DOCTYPE html>
<html>
<head>
${title.toString()}
${scripts.toString()}
${links.toString()}
${metas.toString()}
</head>
<body>
Your awesome <div id="react-root"></div>
</body>
</html>`
);It's actually required to use rewind() on server-side to avoid memory leaks. See react-side-effect documentation.
If you rehydrate your React app client-side, you should call Freud.sync() after the app gets re-rendered.
A good place is the ReactDOM.render() callback:
ReactDOM.render(
<App />,
document.getElementById("app-root"),
() => Freud.sync()
);Which is called every time the App component is updated. If during the lifecycle of your app some components dynamically render Freud tags, remember to call Freud.sync().
Contribution
Typical npm workflow:
git clone https://github.com/mattecapu/freud.git
cd freud
NODE_ENV=development npm i
npm run devLicense
ISC