{"id":20949645,"url":"https://github.com/bitttttten/oatmilk","last_synced_at":"2025-07-23T13:33:00.866Z","repository":{"id":34809737,"uuid":"183809623","full_name":"bitttttten/oatmilk","owner":"bitttttten","description":"Minimal routing library for React.","archived":false,"fork":false,"pushed_at":"2022-12-09T21:36:37.000Z","size":5721,"stargazers_count":35,"open_issues_count":17,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-02T19:53:23.608Z","etag":null,"topics":["es6","hooks","react","reactjs","router","routing"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bitttttten.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-04-27T18:42:10.000Z","updated_at":"2023-06-01T14:40:49.000Z","dependencies_parsed_at":"2023-01-15T09:30:56.336Z","dependency_job_id":null,"html_url":"https://github.com/bitttttten/oatmilk","commit_stats":null,"previous_names":[],"tags_count":51,"template":false,"template_full_name":null,"purl":"pkg:github/bitttttten/oatmilk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitttttten%2Foatmilk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitttttten%2Foatmilk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitttttten%2Foatmilk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitttttten%2Foatmilk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bitttttten","download_url":"https://codeload.github.com/bitttttten/oatmilk/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitttttten%2Foatmilk/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266689100,"owners_count":23969140,"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","status":"online","status_checked_at":"2025-07-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["es6","hooks","react","reactjs","router","routing"],"created_at":"2024-11-19T00:41:18.805Z","updated_at":"2025-07-23T13:33:00.807Z","avatar_url":"https://github.com/bitttttten.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"docs/img/oatmilk-cropped.png\" alt=\"oatmilk\" width=\"380\" height=\"auto\" style=\"height: auto;\" /\u003e\n\n# oatmilk\n\n[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n[![Github release version](https://img.shields.io/github/tag/bitttttten/oatmilk.svg)](https://github.com/bitttttten/oatmilk/releases)\n[![Commits since release](https://img.shields.io/github/commits-since/bitttttten/oatmilk/v3.2.1.svg)](https://github.com/bitttttten/oatmilk/compare/v3.2.1...master)\n[![npm release version](https://img.shields.io/npm/v/oatmilk.svg)](https://www.npmjs.com/package/oatmilk)\n\n## Introduction\n\noatmilk is a minimal routing library for React.\n\n## Docs\n\n-   [Server rendering](https://github.com/bitttttten/oatmilk/blob/master/docs/server-rendering.md)\n-   [Typescript](https://github.com/bitttttten/oatmilk/blob/master/docs/typescript.md)\n-   [Using Context](https://github.com/bitttttten/oatmilk/blob/master/docs/using-context.md)\n\n## Instructions\n\n### Install\n\n`yarn add oatmilk`\n\n### Wrap your App with your routes\n\nEach route is an object with the required shape:\n\n```sh\n{\n    name: string\n    path: path\n    view: ReactNode\n    onEnter?: function\n    onBeforeExit?: function\n}\n```\n\nWhere `path` is any default pattern of [url-pattern](https://www.npmjs.com/package/url-pattern). The 2 optional properties `onEnter` and `onBeforeExit` are explained in the [transition hooks docs](https://github.com/bitttttten/oatmilk/blob/master/README.md#transition-hooks).\n\nYou must included a route with a name of `notFound` since this is the fallback route. The order of the routes does not matter.\n\n```js App.tsx\nimport oatmilk from 'oatmilk'\n\nconst routes: oatmilk.IRoute[] = [\n    {\n        name: 'home',\n        path: '/',\n        // send in any react node\n        view: () =\u003e \u003cp\u003eThe world never says hello back..\u003c/p\u003e,\n    },\n    {\n        name: 'user',\n        // 'named segment'\n        path: '/user/:id',\n        // use React.lazy to help with code splitting\n        view: React.lazy(() =\u003e import('./Pages/User.tsx')),\n    },\n    {\n        name: 'notFound',\n        path: '/404',\n        // or use @loadable/component for SSR support\n        view: loadable(() =\u003e import('./Pages/NotFound.tsx')),\n    },\n]\n\nReactDOM.render(\n    \u003coatmilk.Provider routes={routes}\u003e\n        \u003cApp /\u003e\n    \u003c/oatmilk.Provider\u003e,\n    document.getElementById('root'),\n)\n```\n\n### Render a RouterView\n\nThe `RouterView` will render the current route's `view`.\n\n```js App.tsx\nexport function App() {\n    return (\n        \u003c\u003e\n            \u003cNavigation /\u003e\n            \u003cHeader /\u003e\n            \u003coatmilk.RouterView /\u003e\n            \u003cFooter /\u003e\n        \u003c/\u003e\n    )\n}\n```\n\n### Render some links\n\nNo need to generate the paths here, oatmilk will find the route and generate a path for you that is derived from the state.\n\n```js App.tsx\nfunction Navigation() {\n    return (\n        \u003c\u003e\n            \u003coatmilk.Link routeName='home'\u003eGo home\u003c/oatmilk.Link\u003e\n            \u003coatmilk.Link routeName='user' state={{ user: 'bitttttten' }}\u003e\n                Go to my page\n            \u003c/oatmilk.Link\u003e\n        \u003c/\u003e\n    )\n}\n```\n\n..and off you go 🎉✨\n\n## API\n\n## useOatmilk\n\noatmilk has a React hook `useOatmilk` that provides routing utilities and information about the current route.\n\nIt returns the interface `oatmilk.IContext` which is:\n\n```js\n{\n    // used to to change routes\n    goTo: (toRouteName: string, toState?: object) =\u003e void\n    // used to generate the href of a link element of a route\n    getHref: (routeName: string, state?: object) =\u003e string\n    // information about the current route\n    route: {\n        name: string\n        path: string\n        view: ReactComponent\n    }\n    // the current state object\n    state: object\n}\n```\n\n### Transition Hooks\n\noatmilk has 2 transition hooks: onEnter, and onBeforeEnter. You can use it for the global routing context, and also for a single route's context.\n\n```js routes.tsx\nimport oatmilk, { IRoute, TRouteState } from 'oatmilk'\n\nexport const routes: IRoutes = [\n    {\n        name: 'home',\n        path: '/',\n        view: HomePage,\n        onEnter: (route: IRoute, state: TRouteState) =\u003e {\n            console.log('I am called as you enter only the home route')\n            ArticlesStore.fetchTrendingArticles()\n            TodoStore.fetchTodos()\n        },\n        onBeforeExit: (route: IRoute, state: TRouteState) =\u003e {\n            console.log('I am called as you exit only the home route')\n        },\n    },\n    {\n        name: 'user'\n        path: '/user/:slug',\n        view: UserPage,\n        onEnter: (route: IRoute, state: TRouteState) =\u003e {\n            UserStore.fetchUserById(state.id)\n        },\n    },\n]\n\nfunction onEnter(route: IRoute, state: TRouteState) {\n    console.log('I am called as you enter any route')\n    analytics.logPageView()\n}\n\nfunction onBeforeExit(route: IRoute, state: TRouteState) {\n    console.log('I am called as you exit any route')\n}\n\nReactDOM.render(\n    \u003coatmilk.RouterProvider routes={routes} onEnter={onEnter} onBeforeExit={onBeforeExit}\u003e\n        \u003cApp /\u003e\n    \u003c/oatmilk.RouterProvider\u003e,\n    document.getElementById('root'),\n)\n```\n\n### Hook callee\n\noatmilk ships with a way to customise how the above hooks are called with a `hookCallee` function. Use this method to inject your own callee to completely customise the transition hooks. This can help with server side rendering by passing in a store on the server and client. Learn about that in [the server rendering docs](https://github.com/bitttttten/oatmilk/blob/master/docs/server-rendering.md).\n\n## Decoupled\n\noatmilk is state first, and everything else is derived from this. The current route is held in state and effects like updating the URL, are managed after the fact. Decoupling your state and data fetching from your view helps you keep a declarative approach to your codebase. It also makes reasoning and testing simplier, and greatly reduces the complexity of server rendering and pre-fetching data.\n\n## Credits\n\nThanks to [probablyup](https://github.com/probablyup)'s [buttermilk](https://github.com/probablyup/buttermilk), which was a project I found after writing the first draft of oatmilk which inspired a lot of changes and inspiration.. and of course the name.\n\nMade possible by\n\n\u003ca href=\"https://soulpicks.com\" target=\"_blank\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/37078572?s=200\u0026v=4\" width=\"64\" height=\"64\"\u003e\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitttttten%2Foatmilk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbitttttten%2Foatmilk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitttttten%2Foatmilk/lists"}