React-Router: Variable Route Parameters

GitHub Repos

💾 Ncoughlin: React-Streams-Client

💾 Ncoughlin: React-Streams-API

Intro

We will continue here working on our Twitch Clone Project called ”Glitch“.

current twitch progress

We can see that we now have a list of streams available and a form to create new ones. We have also already created Redux actions/reducers for all of the additional CRUD functions. We now need to make it so that when we click on one of the edit or delete buttons… we actually perform that action.

Another thing to keep in mind is that we are following the REST convention. So if we are going to edit one of the streams, we want to have that form live at the following url.

/streams/:id/edit or /streams/:id/delete to delete.

This is going to be similar to Express Route Parameters in the sense that we are going to be dealing with variables in the URL.

Let us start by updating our edit and delete buttons on Stream list so that they use our React-Router Link component.

components/StreamList.js
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";

import { fetchStreams } from "../../actions";

class StreamList extends Component {
  componentDidMount() {
    this.props.fetchStreams();
  }

  // check if stream author is current user
  renderAdmin(stream) {
    if (stream.userId === this.props.currentUserId) {
      return (
        <div className="right floated content">
          <Link className="ui button primary" to={`/streams/${stream.id}/edit`}>            Edit          </Link>          <Link            className="ui button negative"            to={`/streams/${stream.id}/delete`}          >            Delete          </Link>        </div>
      );
    }
  }

  renderList() {
    return this.props.streams.map((stream) => {
      return (
        <div className="item" key={stream.id}>
          {this.renderAdmin(stream)}
          <i className="large middle aligned icon camera" />
          <div className="content">
            {stream.title}
            <div className="description">{stream.description}</div>
          </div>
        </div>
      );
    });
  }

  // show "Create Stream" button if user is signed in
  renderCreate() {
    if (this.props.isSignedIn) {
      return (
        <div style={{ textAlign: "right" }}>
          <Link to="/streams/new">
            <button className="ui green basic button">Create Stream</button>
          </Link>
        </div>
      );
    }
  }

  render() {
    return (
      <div>
        <h2>Streams</h2>
        <div className="ui celled list">{this.renderList()}</div>
        {this.renderCreate()}
      </div>
    );
  }
}

const mapStateToProps = (state) => {
  return {
    streams: Object.values(state.streams),
    currentUserId: state.auth.userId,
    isSignedIn: state.auth.isSignedIn,
  };
};

export default connect(mapStateToProps, { fetchStreams })(StreamList);

Creating Variable URL Routes

and then we just need to update our route parameters, which are currently living inside our main app file.

App.js
import React, { Component } from "react";
import { BrowserRouter, Route } from "react-router-dom";

import Header from "./Header";
import StreamList from "./streams/StreamList";
import StreamCreate from "./streams/StreamCreate";
import StreamDelete from "./streams/StreamDelete";
import StreamEdit from "./streams/StreamEdit";
import StreamShow from "./streams/StreamShow";

class App extends Component {
  render() {
    return (
      <div className="ui container">
        <BrowserRouter>
          <Header />
          <Route path="/" exact component={StreamList} />
          <Route path="/streams/new" exact component={StreamCreate} />
          <Route path="/streams/:id/delete" exact component={StreamDelete} />          <Route path="/streams/:id/edit" exact component={StreamEdit} />          <Route path="/streams/show" exact component={StreamShow} />
        </BrowserRouter>
      </div>
    );
  }
}

export default App;

And note that we use : to signify a variable in the URL, just like we do when using Express.

Accessing Variables in Components

And just like in Express, we need to be able to extract this variable in our destination and use it to render content. In Express we do this with req.params. In React this information gets passed down to the component automatically by the React-Router Route component as a prop called match.params. Sound familiar?

That’s it, it’s really so easy. Any variable that we put in the route path will end up as a match.params prop in the destination components.