Comments (8)
Thanks, @koistya, but without this part "router" unuseful for me. And I don't know why you call this library a "router".
from universal-router.
It doesn't handle the navigation part just routing. In order to watch for changes in URL you may want to use history
npm module. Example:
// history.js
import createBrowserHistory from 'history/createBrowserHistory';
export default createBrowserHistory();
// main.js
import history from './history';
function render(location) { ... }
history.listen(location => {
render(location);
});
render(history.location);
// Links
import history from './history';
function onClick(event) {
event.preventDefault();
history.push(event.currentTarget.attr('href'));
}
from universal-router.
It's by decoupling from the history
API that the universal
-router is able to be called universal
afterall @PaulMaly . Otherwise you wouldn't be able to use it in another non browser environment such as NodeJS Http server.
It's quite easy as demonstrated by @koistya to connect the universal-router to the History and Location API.
Still, I got a question @koistya about how this example that you gave above works together with React. Is it really a good approach to call render(history.location);
in the root of the application??? I mean... it doesn't sound so performatic. You're reloading the whole stuff!!
Perhaps a more well located approach with a hoc
maybe....
from universal-router.
@BernardoS,
UniversalRouter allows to use routing code in different environments but entry points are usually platform specific anyway. See Isomorphic (universal) JavaScript concepts.
History
module is not required. You may use the native History API if you want, it's up to you.
Yes, it is normal to re-render the app on location change. React takes care about performant updates. See Design Principles of React.js.
One more example:
// router.js - isomorphic (universal) code
import UniversalRouter from 'universal-router'
import React from 'react'
export default new UniversalRouter([ // all your routes here
{ path: '/', action: () => <h1>Home</h1> },
{ path: '/users', action: () => <h1>Users</h1> },
{ path: '/user/:id', action: (ctx) => <h1>User #{ctx.params.id}</h1> }
])
// client.js - entry point for browser
import ReactDOM from 'react-dom'
import router from './router.js'
const container = document.getElementById('app')
async function render() {
const page = await router.resolve(location.pathname)
ReactDOM.render(page, container)
}
render() // run client-side application
// in case if you need single page application
window.addEventListener('click', event => {
if (event.target.tagName === 'A') {
event.preventDefault()
const anchor = event.target
const state = null
const title = anchor.textContent
const url = anchor.pathname + anchor.search + anchor.hash
history.pushState(state, title, url)
render()
}
})
// server.js - entry point for node.js server
import http from 'http'
import ReactDOMServer from 'react-dom/server'
const server = http.createServer(async (req, res) => {
const page = await router.resolve(req.url)
const html = ReactDOMServer.renderToString(page)
res.end(`<!doctype html><div id="app">${html}</div>`);
});
server.listen(3000); // run server-side application
Demo: https://jsfiddle.net/frenzzy/fr1q4gne/
from universal-router.
@frenzzy I don't see where in the Design Principles of React.js you're seeing that is a good practice to do that.
Thanks for the other example but still, It seems that rendering the whole tree is a thing to be avoided in a React application. It apperently has the same performance as changing the state of the root component in the tree, and as you can see in multiple places and frameworks, such as Redux and Flux, the idea is to re-render the closer to the leaves in the tree as possible, that's why the normal practice in a Redux
environment is to call the connect
hoc
to those leaves.
I'd love to see a big complex example of this re-rendering the root of the application idea in practice to see if i'm not going to suffer performance issues
from universal-router.
The top-level element of any multi-page web application is the page. The only way to change a page is to replace it with a new one, which usually means changing the whole tree. The only case the whole tree update is not desirable when both pages contain the same elements. React cares about it under the hood by skipping DOM updates (React Only Updates What's Necessary). But in memory (in virtual-DOM) react will re-render the whole tree by default and there are some optimization techniques (Avoid Reconciliation).
from universal-router.
Still. Even if (React Only Updates What's Necessary) it also calls shouldComponentUpdate
on every re-render cycle, even if the response is equall. In other words, even if React takes care of not reloading unecessary things, it doesn't mean that React is not doing a hard proccess on the background. Re-calling the render method on the root of the tree is a way more complex rendering lifecycle than calling in a leaf in the tree.
Saying with an example. If I had three routes like /
, /items
and /items/:id
, where basically one route increments the other in the React virtual-dom tree: <Root><Items><Item id={params.id}/></Items></Root>
.
If I were only in /
then only <Root/>
will appear. If I were in /items
than <Root><Items></Items></Root>
. The same way, if I were in the /items/123
the whole tree would appear.
You're basically suggesting that it's a good approach to call the whole process of validation of the whole tree to navigate through this routes. But this is an incremental case, where there's no reason to re-render <Root/>
or <Items/>
every time I change the :id
parameters in the route, you got me now?
I got you're saying is no big deal because it's not gonna cause a re-render in the DOM itself, but it will re-render the whole virtual-dom tree. Therefore, doesn't seem like a good approach if you have a big application, this re-render could be too costy.
I know most of the routers do this, and that's the normal defacto way, but the new version of React Router has a little bit more elegant approach, where it only re-renders what has really changed.
from universal-router.
My mistake @frenzzy . I couldn't be more wrong when I said that
the new version of React Router has a little bit more elegant approach, where it only re-renders what has really changed.
I've got a little puzzled with React Router V4 and decided to do the exact test that I proposed abose
import React, {Component} from 'react'
import {Route, Link} from 'react-router-dom'
export default class App extends Component {
render () {
return (
<div>
<ul>
<li><Link to="/">Root</Link></li>
<li><Link to="/items">Items</Link></li>
<li><Link to="/items/123">Item 123</Link></li>
<li><Link to="/items/124">Item 124</Link></li>
</ul>
<Route path="/" component={Root}/>
</div>
)
}
}
class Root extends Component {
render () {
console.log('render Root')
return <div>
this is Root
<Route path="/items" component={Items}/>
</div>
}
}
class Items extends Component {
render () {
console.log('render Items')
return <div>
this is Items
<Route path="/items/:id" component={Item}/>
</div>
}
}
class Item extends Component {
render () {
console.log(`render Item with id ${this.props.match.params.id}`)
return <div>
this is Item {this.props.match.params.id}
</div>
}
}
Ends up that the react-router v4 does the same proccess o re-rendering all the components that are connected, no matter if the changes are only in the Item
Component
from universal-router.
Related Issues (20)
- bad documentation in 'Getting Started' page HOT 1
- How does universal router handle conflicts? HOT 1
- Question: Routing based on backend logic HOT 3
- Synchronous operation HOT 3
- Recipe for GraphQL state management vs. Redux would be great HOT 1
- middleware TypeError for not found routes HOT 1
- Getting child route's params in middleware HOT 2
- generateUrls() does not work with universal-router/sync HOT 2
- Update Hyperapp url in README
- BUG: route dose not resolve ? HOT 2
- overriding Route type when initializing UniversalRouter HOT 5
- update path-to-router dependency to latest HOT 1
- TypeScript 3.8.3: type checking failing HOT 9
- Incorrect TypeScript RouteParams Interface HOT 2
- Middlware approach context.next and redirection HOT 2
- Bug: Empty children array shouldnt be required when dynamically defining routes HOT 2
- Nested url generation HOT 2
- Simple Change: Make resolveRoute a class member of UniversalRouter instead of privately scoped HOT 1
- how to handle "not found (404)" page? HOT 1
- Redirects?? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from universal-router.