Dev

By Carlos Santana on
Reading time: 3 minutes

React-SPWrc.png

If you read our last post: Implementing React Router in our React application you know how to create basic routes, but as I said in the last post, I'll show you how to add params in our routes to have different behaviors on our application based on the routes parameters.

For this explanation, we will create a component called Posts (src/components/Posts/index.jsx), and this is the skeleton of our Posts component: 

import React, { Component } from 'react';
import './Posts.css';

class Posts extends Component {
  constructor() {
    super();

    // For now we are going to add our posts to our 
    // local state, but normally this should come 
    // from some a service.
    this.state = {
      posts: [ {
        id: 1,
        title: 'My post 1',
        content: 'The content 1'
      },
      {
        id: 2,
        title: 'My post 2',
        content: 'The content 2'
      },
      {
        id: 3,
        title: 'My post 3',
        content: 'The content 3'
      },
      ]
    };
  }

  render() {
    return (
      <div className="Posts">
        <h1>Posts</h1>
      </div>
    );
  }
}

export default Posts;
File: src/components/Posts/index.jsx

Then the CSS we will use is this one:

.Posts ul {
  list-style: none;
  margin: 0;
  margin-bottom: 20px;
  padding: 0;
}

.Posts ul li {
  padding: 10px;
}

.Posts a {
  color: #ccc;
  text-decoration: none;
}

.Posts a:hover {
  color: #fff;
  text-decoration: none;
}
File: src/components/Posts/Posts.css

After you create those files then you can add the Posts component into your routes file, we will add it with the route: /blog.

// Dependencies
import React from 'react';
import { Route, Switch } from 'react-router-dom';

// Components
import App from './components/App';
import Home from './components/Home';
import About from './components/About';
import Contact from './components/Contact';
import Error404 from './components/Error/404';
import Posts from './components/Posts';

const AppRoutes = () => (
  <App>
    <Switch>
      <Route path="/" component={Home} exact />
      <Route path="/about" component={About} exact />
      <Route path="/contact" component={Contact} exact />
      <Route path="/blog" component={Posts} exact />
      <Route component={Error404} />
    </Switch>
  </App>
);

export default AppRoutes;
File: src/routes.jsx

Now run the application and you should be able to see the component when you go to http://localhost:3000/blog.

PostsComponent-SGQrM.png

Now in our Posts component, we can render the posts using a map function.

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import './Posts.css';

class Posts extends Component {
  constructor() {
    super();

    // For now we are going to add our posts to our
    // local state, but normally this should come
    // from some a service.
    this.state = {
      posts: [{
        id: 1,
        title: 'My post 1',
        content: 'The content'
      },
      {
        id: 2,
        title: 'My post 2',
        content: 'The content'
      },
      {
        id: 3,
        title: 'My post 3',
        content: 'The content'
      }]
    };
  }

  renderPosts = posts => (
    <ul>
      {posts.map(post => (
        <li key={post.id}>
          <Link to={`/blog/${post.id}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  );

  render() {
    const { posts } = this.state;

    return (
      <div className="Posts">
        <h1>Posts</h1>

        {this.renderPosts(posts)}
      </div>
    );
  }
}

export default Posts;
File: src/components/Posts/index.jsx

As you can see we are using the <Link> component (this will generate an <a> tag) and is pointing to /blog/post.id. Now we need to add a new route where we will specify the parameter we want to catch from the url.

// Dependencies
import React from 'react';
import { Route, Switch } from 'react-router-dom';

// Components
import App from './components/App';
import Home from './components/Home';
import About from './components/About';
import Contact from './components/Contact';
import Error404 from './components/Error/404';
import Posts from './components/Posts';

const AppRoutes = () => (
  <App>
    <Switch>
      <Route path="/" component={Home} exact />
      <Route path="/about" component={About} exact />
      <Route path="/contact" component={Contact} exact />
      <Route path="/blog" component={Posts} exact />
      <Route path="/blog/:postId" component={Posts} exact />
      <Route component={Error404} />
    </Switch>
  </App>
);

export default AppRoutes;
File: src/routes.jsx

Matching our routes

React Router has a special prop called match, which is an object that contains all the data related to the executed route, you can extract it from the this.props object like this: 

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import './Posts.css';

class Posts extends Component {
  constructor() {
    super();

    // For now we are going to add our posts to our
    // local state, but normally this should come
    // from some a service.
    this.state = {
      posts: [{
        id: 1,
        title: 'My post 1',
        content: 'The content 1'
      },
      {
        id: 2,
        title: 'My post 2',
        content: 'The content 2'
      },
      {
        id: 3,
        title: 'My post 3',
        content: 'The content 3'
      }]
    };
  }

  renderPosts = posts => (
    <ul>
      {posts.map(post => (
        <li key={post.id}>
          <Link to={`/blog/${post.id}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  );

  renderSinglePost = ({ title, content }) => (
    <>
      <h2>{title}</h2>
      <p>{content}</p>
    </>
  )

  render() {
    // Let's see what contains our props object.
    console.log(this.props);

    // We got the postId param from match object.
    const { match: { params: { postId } } } = this.props;

    // All posts
    const { posts } = this.state;

    // By default our selectedNote is false
    let selectedPost = false;

    if (postId > 0) {
      // If the postId is higher than 0 then we filter it from our
      // posts array.
      selectedPost = posts.filter(note => note.id === Number(postId))[0];
    }

    return (
      <div className="Posts">
        <h1>Posts</h1>

        {/* We render our selectedNote or all notes */}
        {selectedPost
          ? this.renderSinglePost(selectedPost)
          : this.renderPosts(posts)}
      </div>
    );
  }
}

export default Posts;
File: src/components/Posts/index.jsx

I added a console.log to the code so we can see the match object:

MatchObject-D3IFm.png

Now if you click in some link, let's say on My post 3, you will see this:

MyPost3-hywGy.png

Adding menu to the Header

If you want to add a menu on the Header to navigate between all our components you can modify the App.js like this:

import React, { Component } from 'react';
import { element } from 'prop-types';
import { Link } from 'react-router-dom';
import logo from '../shared/images/logo.svg';
import './App.css';

class App extends Component {
  render() {
    const { children } = this.props;

    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <ul className="menu">
            <li><Link to="/">Home</Link></li>
            <li><Link to="/about">About</Link></li>
            <li><Link to="/blog">Blog</Link></li>
            <li><Link to="/contact">Contact</Link></li>
          </ul>
        </header>

        {children}
      </div>
    );
  }
}

App.propTypes = {
  children: element
};

export default App;
File: src/components/App.jsx

I moved out the {children} from <header>, and then I edited the App.css to do the header smaller and have the content in a white background:

Only members can see all the codes
You can Login or Sign Up

File: src/components/App.css

If you followed everything correctly, then you should see your app like this:

AppWithMenu-mT6W9.png

If you liked this post and you want to learn more about React, you can buy my React Cookbook.

avatarLeave a comment

Your comment

Only members can comment. You can Login or Sign Up