Nested routes - React Router v4

Codul este aici https://codesandbox.io/s/48yym1j9p7
În tutorialul pe care îl parcurg se folosește react router v2 dar vreau să folosesc ultima versiune.
Nu mi dau seama cum să randez componenta Post
Am încercat cu ({match}) , dar nu mi dau seama unde greșesc.

Am vazut doua probleme:

1.Partea de Route path trebuie sa specifici de la specific->generic pentru a evita sa intre intr-un path care nu vrei, sau folosesti path-uri complet diferite, de exemplu:

Not ok:

test
test/one
test/one/two

Ok:

test/one/two
test/one
test

2.Pentru componenta ai nevoie sa injectezi middleware-ul care sa seteze proprietatile de router.
Inainte:

export default Post;

Dupa:

export default withRouter(Post);

Varianta cu modificarile de mai sus o gasesti aici: https://codesandbox.io/s/moxwzyyko9

1 Like

<Route path="/posts" render={() => <Posts posts={PostsContent} />} />

Fiinca mai ai o ruta ce contine ‘/posts’, trebuie sa specifici la cea mai scurta varianta keywordul ‘exact’:

<Route exact path="/posts" render={() => <Posts posts={PostsContent} />} />

A doua problema este ca folosesti render in loc de component. Daca vrei sa folosesti render, trebuie sa transmiti mai departe datele care te intereseaza din props. De exemplu ‘props.match.params.id’ :

<Route path="/posts/:id" render={(props) => <Post posts={PostsContent} match={props.match}/>} />

Iar in Post.jsx vei avea access la props.match.params.id (la v4 au bagat params in match). Nu ai nevoie de props.route din moment ce trimiti posturile prin props (poti sa accesezi direct props.posts).

Si in final, repet ce spunea colegul mai sus: conteaza ordinea rutelor din Switch. Switch cauta de sus in jos prima ruta care se potriveste cu path-ul curent, si cand gaseste una, le ignora pe restul dupa ea.

2 Likes

In bookmarks aveam acest video :

1 Like

Mulțumesc pentru soluții și recomandări.
Aleg să folosesc composition + render() (varianta propusă de @adrian.tiberius ) în loc de HOC (varianta propusă de @pghoratiu ) pentru că mi se pare mai usoară această abordare, pentru cunoștiintele care le am în acest moment.
@isti37 i-am făcut bookmark la video. Mi-a dat o idee de aplicație care m-ar ajuta să înțelez cum se face rutarea pe frontend.
Dacă mai aveți link-uri cu materiale scrise/în format video, despre rutare pe frontend , sunt binevenite.

Recomand sa inveti sa lucrezi si cu un state container (eu am folosit redux), pentru aplicatii mai complexe e greu sa lucrezi fara. Se poate integra usor cu react si react-router si automat ai in store informatii despre ruta curenta plus alte beneficii cand vine vorba de reconstructia state-ului aplicatiei.

1 Like

BTW ce am mai gasit printre bookmarks cautand printre chestii :
https://pshrmn.github.io/route-tester/

Then this is the best article hands down on redux :
Daca esti mai putin curajos incepe de aici : (respectiv iti explica foarte clar cand ai nevoie de redux, chiar mult prea clar)

Daca esti mai hardcore incepe de aici : (practic cu mongodb+express+react+redux)

Iar daca ceva tot nu e clar (mie nu mi-a fost clar ce e cu thunk si saga si side-effects) vezi :
http://blog.isquaredsoftware.com/ - idiomatic redux 1 si 2, respectiv thoughts on thunks, sagas and observables

Totusi daca vrei ceva simplu, nu iti mai ajunge setState din ceva motiv lasa redux si foloseste mobx, te scapa de multa durere de cap la inceput. Nu mai ai de invatat aproape nimic, avantajele majore ale lui redux incep de la aplicatii complexe si echipe.

O alta problema e ca la testare nu iti mai ajunge sa testezi functiile daca nu sunt pure, trebuie sa testezi si fiecare reducer.

O problema care nu e o problema daca nu te duci dupa recomandari e cu side-effects, devine o problema daca ai api-uri asincron pe care vrei sa le pui in reducer.
https://decembersoft.com/posts/what-is-the-right-way-to-do-asynchronous-operations-in-redux/

Daca dai un ochi peste redux-saga o sa vezi ca e chineza doar ca sa nu faci un call direct din reducer. Iar solutia simpla, redux-thunk care iti permite sa faci dispatch la functii iti da cam multa putere.

1 Like

Tot legat de trecerea de la react-router v2 la v4.
În fișierul App.js am o componentă scrisă folosind this.props.children

import React, {PropTypes} from 'react'

class App extends React.Component {
  render() {
    return <div className="container-fluid">
      <p>header here..</p>
      {this.props.children}
    </div>
  }
}

App.propTypes = {
  children: PropTypes.object.isRequired
}

export default App

În fișierul routes.js am toate rutele folosind react-router v2

import React from 'react'
import { BrowserRouter, Route, IndexRoute } from 'react-router'
import App from './components/App'
import HomePage from './components/HomePage'
import AboutPage from './components/AboutPage'

export default (
  <Route path="/" component={App}>
    <IndexRoute component={HomePage} />
    <Route path="about" component={AboutPage} />
  </Route>
)

În codul vechi, toate componentele erau randate în felul

import 'babel-polyfill'
import React from 'react'
import {render} from 'react-dom'
import {Router, browserHistory} from 'react-router'
import routes from './routes'
import './styles/styles.css'
import '../node_modules/bootstrap/dist/css/bootstrap.min.css'

render(
  <Router history={browserHistory} routes={routes} />,
  document.getElementById('app')
)

A trebuit să modific componenta App ca să reușesc să randez componentele.

import React from 'react'
import PropTypes from 'prop-types'

class App extends React.Component {
  render() {
    return <div className="container-fluid">
      <p>header here..</p>
    </div>
  }
}

export default App

Cum să fac să păstrez forma inițială pentru componenta App astfel încât componentele HomePage și AboutPage să fie randate ca și copii ale acesteia?

Codul este aici https://codesandbox.io/s/6yvp0jlvkz

Faci o componenta App (fara exact) si HomePage (cu exact), doar asa e cel mai logic nu ? :

const App = () => (
    <Switch>
      <Route path='/' component={HomePage}/>
      <Route path='/about' component={AboutPage}/>
      <Route component={Unknown}/>
    </Switch>
)
const HomePage = () => (
    <Switch>
      <Route exact path='/' component={Welcome}/>
      <Route path='/prices' component={Prices}/>
    </Switch>
)

Daca vrei sa mentii totul intr-un singur fisier exista :

https://webuild.envato.com/blog/a-real-word-story-of-upgrading-react-router-to-v4-in-an-isomorphic-app/

Eu as organiza codul astfel:

  • routes.js:
import React from 'react'
import { Route, Switch, Redirect } from 'react-router-dom'
import HomePage from './components/HomePage'
import AboutPage from './components/AboutPage'

export default (
  <Switch>
    <Route exact path="/" component={HomePage} />
    <Route path="/about" component={AboutPage} />
    <Redirect path="*" to="/" />
  </Switch>
)
  • App.js:
import React, {PropTypes} from 'react';
import routes from './routes';

class App extends React.Component {
  render() {
    return (
      <div className="container-fluid">
        <p>header here..</p>
        {routes}
      </div>
    );
  }
}

App.propTypes = {
}

export default App

Aici probabil si headerul poti sa-l transformi intr-o componenta de sine statatoare din moment ce cred ca o sa contina mai mult decat un paragraf.

  • render.js:
import 'babel-polyfill'
import React from 'react'
import {render} from 'react-dom'
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import './styles/styles.css'
import '../node_modules/bootstrap/dist/css/bootstrap.min.css'

render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('app')
)
2 Likes