{"id":14384858,"url":"https://github.com/elierotenberg/react-prepare","last_synced_at":"2025-04-10T21:11:51.013Z","repository":{"id":12445679,"uuid":"71832350","full_name":"elierotenberg/react-prepare","owner":"elierotenberg","description":"Prepare you app state for async server-side rendering and more!","archived":false,"fork":false,"pushed_at":"2022-04-10T20:33:07.000Z","size":105,"stargazers_count":100,"open_issues_count":6,"forks_count":16,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-10T21:11:44.656Z","etag":null,"topics":["async-await","react","redux","server-side-rendering","universal"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elierotenberg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-10-24T21:09:21.000Z","updated_at":"2023-07-28T10:35:02.000Z","dependencies_parsed_at":"2022-08-07T06:17:00.342Z","dependency_job_id":null,"html_url":"https://github.com/elierotenberg/react-prepare","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elierotenberg%2Freact-prepare","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elierotenberg%2Freact-prepare/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elierotenberg%2Freact-prepare/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elierotenberg%2Freact-prepare/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elierotenberg","download_url":"https://codeload.github.com/elierotenberg/react-prepare/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248298317,"owners_count":21080320,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async-await","react","redux","server-side-rendering","universal"],"created_at":"2024-08-28T18:01:43.699Z","updated_at":"2025-04-10T21:11:50.994Z","avatar_url":"https://github.com/elierotenberg.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"## react-prepare\n\n`react-prepare` allows you to have you deeply nested components with asynchronous dependencies, and have everything just work with server-side rendering.\n\nThe typical use-case is when a deeply-nested component needs to have a resource fetched from a remote HTTP server, such as GraphQL or REST API. Since `renderToString` is synchronous, when you call it on your app, this component won't render correctly.\n\nOne solution is to have a central router at the root of your application that knows exactly what data needs to be fetched before rendering. But this solution doesn't fit the component-based architecture of a typical React app. You want to declare data dependencies at the component level, much like your declare your props.\n\nThis is exactly what `react-prepare` does: it allows you to declare asynchronous dependencies at the component level, and make them work fine with server-side rendering as well as client-side rendering.\n\n`react-prepare` is agnostic and can be used vanilla, but it comes with a tiny helper that makes it extremely easy to use along `redux` and `react-redux` (see examples below).\n\n#### Example with `react-redux`\n\nLet's assume you have defined an async action creator `fetchTodoItems(userName)` which performs HTTP request to your server to retrieve the todo items for a given user and stores the result in your redux state.\n\nYour `TodoList` component definition would look like this:\n\n```js\nimport { dispatched } from 'react-prepare';\nimport { connect } from 'react-redux';\nimport { compose } from 'redux';\n\nimport { fetchTodoItems } from './actions';\n\nconst enhance = compose(\n  dispatched(({ userName }, dispatch) =\u003e dispatch(fetchTodoItems(userName))),\n  connect(({ todoItems }) =\u003e ({ items: todoItems }),\n);\n\nconst TodoList = ({ items }) =\u003e \u003cul\u003e{items.map((item, key) =\u003e\n  \u003cli key={key}\u003e{item}\u003c/li\u003e\n\u003c/ul\u003e}\u003c/ul\u003e;\n\nexport default enhance(TodoList);\n```\n\nAnd your server-side rendering code would look like this:\n\n```js\nimport { renderToString } from 'react-dom/server';\nimport { createStore, applyMiddleware } from 'redux';\nimport thunkMiddleware from 'redux-thunk';\nimport { Provider } from 'react-redux';\nimport prepare from 'react-prepare';\n\nimport reducer from './reducer';\n\nasync function serverSideRender(userName) {\n  const store = createStore(reducer, applyMiddleware(thunkMiddleware));\n  const app = \u003cProvider store={store}\u003e\n    \u003cTodoList userName={userName} /\u003e\n  \u003c/Provider\u003e;\n  await prepare(app);\n  return {\n    html: renderToString(app),\n    state: store.getState(),\n  };\n}\n```\n\nYour client could re-use the data fetched during server-side rendering directly, eg. assuming your injected it in `window.__APP_STATE__`:\n\n```js\nconst store = createStore(reducer, JSON.parse(window.__APP_STATE__));\nrender(\u003cProvider store={store}\u003e\n  \u003cTodoList userName={userName} /\u003e\n\u003c/Provider\u003e, document.getElementById('app'));\n```\n\n**For a complete example of a fully-functional app using `react-prepare` in conjunction with `redux`, see the [react-prepare-todo](https://github.com/elierotenberg/react-prepare-todo) repository.**\n\n### API\n\n#### `dispatched(sideEffect: async(props, dispatch), opts)(Component)`\n\nHelper to use `prepared` more simply if your side effects consists mostly of dispatching redux actions.\n\nIn the body of the `sideEffect` function, you can use the `dispatch` function to dispatch redux actions, typically\nrequesting data from an asynchronous source (API server, etc.).\nFor example, let's assume you have defined an async action creator `fetchTodoItems(userName)` that fetches the todo-items from a REST API,\nand that you are defining a component with a `userName` prop. To decorate your component, your code would look like:\n\n```js\nclass TodoItems extends React.PureComponent { ... }\n\nconst DispatchedTodoItems = dispatched(\n  ({ userName }, dispatch) =\u003e dispatch(fetchTodoItems(userName))\n)(TodoItems);\n```\n\nThe decorated component will have the following behavior:\n\n- when server-side rendered using `prepare`, `sideEffect` will be run and awaited before the component is rendered; if `sideEffect` throws, `prepare` will also throw.\n- when client-side rendered, `sideEffect` will be called on `componentDidMount` and `componentWillReceiveProps`.\n\n`opts` is an optional configuration object passed directly to the underlying `prepared` decorator (see below).\n\n#### `prepared(sideEffect: async(props, context), opts)(Component)`\n\nDecorates `Component` so that when `prepare` is called, `sideEffect` is called (and awaited) before continuing the rendering traversal.\n\nAvailable `opts` is an optional configuration object:\n\n- `opts.pure` (default: `true`): the decorated component extends `PureComponent` instead of `Component`.\n- `opts.componentDidMount` (default: `true`): on the client, `sideEffect` is called when the component is mounted.\n- `opts.componentWillReceiveProps` (default: `true`): on the client, `sideEffect` is called again whenever the component receive props.\n\n#### `async prepare(Element)`\n\nRecursively traverses the element rendering tree and awaits the side effects of components decorated with `prepared` (or `dispatched`).\nIt should be used (and `await`-ed) *before* calling `renderToString` on the server. If any of the side effects throws, `prepare` will also throw.\n\n### Notes\n\n`react-prepare` tries hard to avoid object keys conflicts, but since React isn't very friendly with `Symbol`, it uses a special key for its internal use.\nThe single polluted key in the components key namespace is `@__REACT_PREPARE__@`, which shouldn't be an issue.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felierotenberg%2Freact-prepare","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felierotenberg%2Freact-prepare","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felierotenberg%2Freact-prepare/lists"}