` links to use client-side history navigation.
138 |
139 |
140 | ### Size comparison
141 |
142 | Gzip:
143 | - react-context-router: 19.04 KB (5.13 KB without React)
144 | - react-router: 40.29 KB with React
145 | - Baseline react 14.52 KB
146 |
147 | *Results from [bundle-size](https://npmjs.com/package/bundle-size)*
148 |
149 | MIT License
150 |
151 |
--------------------------------------------------------------------------------
/compositor.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jxnblk/react-context-router",
3 | "version": "0.1.4",
4 | "libraries": {
5 | "xv": "^1.1.19"
6 | },
7 | "title": "React Context Router",
8 | "branch": "",
9 | "style": {
10 | "name": "Brutalist",
11 | "componentSet": {
12 | "nav": "nav/BasicNav",
13 | "header": "header/BasicHeader",
14 | "article": "article/MarkdownArticle",
15 | "footer": "footer/BasicFooter"
16 | },
17 | "fontFamily": "Consolas, \"Liberation Mono\", Menlo, Courier, monospace",
18 | "heading": {},
19 | "typeScale": [
20 | 48,
21 | 32,
22 | 20,
23 | 18,
24 | 16,
25 | 14,
26 | 12
27 | ],
28 | "layout": {
29 | "maxWidth": 1024,
30 | "fluid": true
31 | },
32 | "colors": {
33 | "text": "#333",
34 | "background": "#fff",
35 | "primary": "#666",
36 | "secondary": "#888",
37 | "highlight": "#1f80ff",
38 | "muted": "#f6f6f6",
39 | "border": "#eee"
40 | }
41 | },
42 | "content": [
43 | {
44 | "component": "nav",
45 | "links": [
46 | {
47 | "href": "https://github.com/jxnblk/react-context-router",
48 | "text": "GitHub"
49 | },
50 | {
51 | "href": "https://npmjs.com/package/react-context-router",
52 | "text": "npm"
53 | }
54 | ]
55 | },
56 | {
57 | "component": "header",
58 | "heading": "react-context-router",
59 | "subhead": "Minimal React router based on React context",
60 | "children": [
61 | {
62 | "component": "ui/TweetButton",
63 | "text": "react-context-router: Minimal React router based on React context",
64 | "url": null
65 | },
66 | {
67 | "component": "ui/GithubButton",
68 | "user": "jxnblk",
69 | "repo": "react-context-router"
70 | }
71 | ],
72 | "text": "v1.1.0"
73 | },
74 | {
75 | "component": "article",
76 | "metadata": {
77 | "source": "github.readme"
78 | },
79 | "html": "\nMinimal React router based on React context
\n
\nnpm i react-context-router React Router is an excellent routing solution,\nbut sometimes it does a lot more than you need it to.\nThis is intended to be a smaller option with a simpler API.
\nFeatures \n\nSmall-ish package ~5KB \nSimple API \nOne higher order component and two components: Router & Link \nPass props directly to any component \nPass anything through route context \n \nUsage \n\nimport React from 'react' \nimport { createRouter, Link } from 'react-context-router' \n\nconst NotFound = () => <div > Not Found</div > \n\nconst Nav = () => (\n <nav>\n <Link href='/' children='Home' />\n <Link href='/posts/1' children='First Post' />\n </nav>\n)\n\nclass App extends React.Component {\n render () {\n const { route } = this.props\n const Comp = route.component || NotFound\n\n return (\n <div>\n <Nav />\n <Comp />\n </div>\n )\n }\n}\n\nexport default createRouter(App) \nimport React from 'react' \nimport ReactDOM from 'react-dom' \nimport App from './App' \nimport Index from './Index' \nimport Post from './Post' \n\nconst routes = [\n {\n path: '/' ,\n \n \n \n component: Index\n },\n {\n path: '/posts/:id' ,\n component: Post\n }\n]\n\nconst div = document .getElementById('app' )\n\nReactDOM.render(<App routes ={routes} > , div) Server-side rendering \nPass a pathname
to the Router component to populate the context for a particular route.
\nconst React = require ('react' )\nconst ReactDOM = require ('react-dom' )\nconst h = React.createElement\nconst App = require ('./App' )\n\nconst routes = [\n {\n path: '/' ,\n name: 'Index' \n },\n {\n path: '/posts/:id' ,\n name: 'Post' \n }\n]\n\nconst html = ReactDOMServer.renderToString(\n h(App, {\n routes,\n \n pathname: '/posts/32' \n })\n)API \ncreateRouter
\nHigher order component that provides history and route data through context.
\nroutes
prop \nArray of route objects. Each route must include a path
.\nAny other value added to the object will be provided through context as the route
object when the location matches the path.
\npathname
prop \nManually pass in a pathname to set the current path for server-side rendering.
\nChild Context \nThe wrapped component provides the following objects as context to its children:
\n\nhistory
wrapped window.history
object with listen
and push
methods \nroute
object from the matching item in the routes
prop. When a path contains parameters they will be passed as route.params
. \n \n<Router />
component \nComponent wrapped with createRouter
, provided as a convenience.
\n<Link />
component \nUsed in place of <a>
links to use client-side history navigation.
\nSize comparison \nGzip:
\n\nreact-context-router: 19.04 KB (5.13 KB without React) \nreact-router: 40.29 KB with React \nBaseline react 14.52 KB \n \nResults from bundle-size
\nMIT License
\n"
80 | },
81 | {
82 | "component": "footer",
83 | "links": [
84 | {
85 | "href": "https://github.com/jxnblk/react-context-router",
86 | "text": "GitHub"
87 | },
88 | {
89 | "href": "https://github.com/jxnblk",
90 | "text": "jxnblk"
91 | }
92 | ]
93 | }
94 | ]
95 | }
--------------------------------------------------------------------------------
/demo/About.js:
--------------------------------------------------------------------------------
1 |
2 | import React from 'react'
3 |
4 | const About = () => {
5 | return (
6 |
7 |
About
8 |
9 | )
10 | }
11 |
12 | export default About
13 |
14 |
--------------------------------------------------------------------------------
/demo/App.js:
--------------------------------------------------------------------------------
1 |
2 | import React from 'react'
3 | import { createRouter, Link } from '../src'
4 |
5 | const NotFound = () => (
6 |
7 | 404
8 |
9 | )
10 |
11 |
12 | class App extends React.Component {
13 | render () {
14 | const { history, route } = this.props
15 |
16 | const sx = {
17 | root: {
18 | fontFamily: '-apple-system, sans-serif'
19 | }
20 | }
21 |
22 | const Comp = route.component || NotFound
23 |
24 | return (
25 |
26 |
App
27 |
28 |
29 |
30 |
31 |
32 | )
33 | }
34 | }
35 |
36 | App.contextTypes = {
37 | history: React.PropTypes.object,
38 | route: React.PropTypes.object
39 | }
40 |
41 | export default createRouter(App)
42 |
43 |
--------------------------------------------------------------------------------
/demo/Detail.js:
--------------------------------------------------------------------------------
1 |
2 | import React from 'react'
3 |
4 | const Detail = (props, context) => {
5 | const { params } = context.route
6 | return (
7 |
8 |
Item Detail {params.id}
9 |
10 | )
11 | }
12 |
13 | Detail.contextTypes = {
14 | route: React.PropTypes.object
15 | }
16 |
17 | export default Detail
18 |
19 |
--------------------------------------------------------------------------------
/demo/Index.js:
--------------------------------------------------------------------------------
1 |
2 | import React from 'react'
3 | import { Link } from '../src'
4 |
5 | const Index = (props, { route }) => {
6 | const links = Array.from({ length: 16 }).map((a, i) => i)
7 |
8 | return (
9 |
10 |
Index
11 |
12 | {links.map(i => (
13 |
14 |
15 |
16 | ))}
17 |
18 |
19 | )
20 | }
21 |
22 | Index.contextTypes = {
23 | route: React.PropTypes.object
24 | }
25 |
26 | export default Index
27 |
28 |
--------------------------------------------------------------------------------
/demo/entry.js:
--------------------------------------------------------------------------------
1 |
2 | import React from 'react'
3 | import ReactDOM from 'react-dom'
4 | import { createRouter, Router } from '../src'
5 | import App from './App'
6 | import Index from './Index'
7 | import About from './About'
8 | import Detail from './Detail'
9 |
10 | const div = document.getElementById('app')
11 |
12 | const routes = [
13 | {
14 | path: '/',
15 | component: Index
16 | },
17 | {
18 | path: '/about',
19 | component: About
20 | },
21 | {
22 | path: '/items/:id',
23 | component: Detail
24 | }
25 | ]
26 |
27 | ReactDOM.render( , div)
28 |
29 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/demo/node-server.js:
--------------------------------------------------------------------------------
1 | // Server-side rendering demo
2 | // Run `node demo/node-server.js` using Node ^v6
3 |
4 | const React = require('react')
5 | const ReactDOMServer = require('react-dom/server')
6 | const { Router, Link } = require('..')
7 | const h = React.createElement
8 |
9 | const App = (props, context) => {
10 | return (
11 | h('div', {}, [
12 | h(Link, { key: 0, href: '/' }, 'Home'),
13 | h('span', { key: 1 }, 'Current route:'),
14 | h('pre', { key: 2 }, JSON.stringify(context.route, null, 2))
15 | ])
16 | )
17 | }
18 | App.contextTypes = {
19 | route: React.PropTypes.object
20 | }
21 |
22 | const routes = [
23 | {
24 | path: '/',
25 | name: 'Index'
26 | },
27 | {
28 | path: '/posts/:id',
29 | name: 'Post'
30 | }
31 | ]
32 |
33 | const html = ReactDOMServer.renderToString(
34 | h(Router, { routes, pathname: '/posts/32' }, [
35 | h(App, { key: 0 })
36 | ])
37 | )
38 |
39 | console.log(html)
40 |
41 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 |
2 | var webpack = require('webpack')
3 |
4 | var configuration = {
5 | browsers: [
6 | 'Firefox'
7 | ],
8 |
9 | singleRun: true,
10 |
11 | files: [
12 | 'karma.js'
13 | ],
14 |
15 | frameworks: [
16 | 'mocha'
17 | ],
18 |
19 | plugins: [
20 | 'karma-firefox-launcher',
21 | 'karma-mocha',
22 | 'karma-mocha-reporter',
23 | 'karma-webpack'
24 | ],
25 |
26 | preprocessors: {
27 | 'karma.js': [ 'webpack' ]
28 | },
29 |
30 | reporters: [ 'mocha' ],
31 |
32 | webpack: {
33 | module: {
34 | loaders: [
35 | {
36 | test: /\.js$/,
37 | exclude: /node_modules/,
38 | loader: 'babel-loader'
39 | },
40 | {
41 | test: /\.json$/,
42 | loader: 'json-loader'
43 | }
44 | ]
45 | },
46 | plugins: [
47 | new webpack.IgnorePlugin(/react\/lib\/ReactContext/),
48 | new webpack.IgnorePlugin(/react\/lib\/ExecutionEnvironment/)
49 | ]
50 | },
51 |
52 | webpackMiddleware: {
53 | noInfo: true
54 | },
55 |
56 | client: {
57 | mocha: {
58 | reporter: 'html',
59 | ui: 'bdd'
60 | }
61 | }
62 | }
63 |
64 | module.exports = function (config) {
65 | config.set(configuration)
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/karma.js:
--------------------------------------------------------------------------------
1 |
2 | const context = require.context('./test', true, /\.js$/)
3 | context.keys().forEach(context)
4 |
5 | module.exports = context
6 |
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-context-router",
3 | "version": "1.1.0",
4 | "description": "Minimal React router based on React context",
5 | "main": "dist/index.js",
6 | "scripts": {
7 | "prepublish": "mkdir -p dist && babel src --out-dir dist",
8 | "build": "NODE_ENV=production webpack -p --progress",
9 | "start": "webpack-dev-server --hot --inline --progress --colors",
10 | "size": "bundle-size ./dist --env production && bundle-size react-router --env production",
11 | "analyze": "webpack --json | webpack-bundle-size-analyzer",
12 | "mocha": "mocha test --compilers js:babel-register",
13 | "test": "karma start"
14 | },
15 | "keywords": [
16 | "react",
17 | "react-component",
18 | "routing",
19 | "router",
20 | "higher-order-component"
21 | ],
22 | "author": "Brent Jackson",
23 | "license": "MIT",
24 | "peerDependencies": {
25 | "react": "^15.0.0"
26 | },
27 | "dependencies": {
28 | "path-to-regexp": "^1.5.1"
29 | },
30 | "devDependencies": {
31 | "babel-cli": "^6.10.1",
32 | "babel-loader": "^6.2.4",
33 | "babel-preset-es2015": "^6.9.0",
34 | "babel-preset-react": "^6.5.0",
35 | "babel-preset-stage-0": "^6.5.0",
36 | "babel-register": "^6.9.0",
37 | "bundle-size": "^0.7.0",
38 | "enzyme": "^2.3.0",
39 | "expect": "^1.20.1",
40 | "json-loader": "^0.5.4",
41 | "karma": "^1.1.1",
42 | "karma-firefox-launcher": "^1.0.0",
43 | "karma-mocha": "^1.1.1",
44 | "karma-mocha-reporter": "^2.0.4",
45 | "karma-webpack": "^1.7.0",
46 | "mocha": "^2.5.3",
47 | "react": "^15.2.1",
48 | "react-addons-test-utils": "^15.2.1",
49 | "react-dom": "^15.2.1",
50 | "react-router": "^2.4.1",
51 | "webpack": "^1.13.1",
52 | "webpack-dev-server": "^1.14.1"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Link.js:
--------------------------------------------------------------------------------
1 |
2 | import React from 'react'
3 |
4 | const Link = ({
5 | href,
6 | ...props
7 | }, {
8 | history,
9 | location
10 | }) => {
11 | const handleClick = (e) => {
12 | e.preventDefault()
13 | history.push(href)
14 | }
15 |
16 | return (
17 |