Coder Social home page Coder Social logo

Comments (8)

PaulMaly avatar PaulMaly commented on May 7, 2024 23

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.

koistya avatar koistya commented on May 7, 2024 7

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.

bsunderhus avatar bsunderhus commented on May 7, 2024 3

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.

frenzzy avatar frenzzy commented on May 7, 2024 1

@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.

bsunderhus avatar bsunderhus commented on May 7, 2024

@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.

frenzzy avatar frenzzy commented on May 7, 2024

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.

bsunderhus avatar bsunderhus commented on May 7, 2024

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.

bsunderhus avatar bsunderhus commented on May 7, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.