Parameters in routes

We have prepared most of the work required to add a new user route. Open up the router.js file again. Add the new route, as follows:

<PrivateRoute path="/user/:username" component={props => <User {...props} changeLoginState={this.props.changeLoginState}/>} loggedIn={this.props.loggedIn}/>

The code contains two new elements, as follows:

  • The path that we entered is /user/:username. As you can see, the username is prefixed with a colon, telling React Router to pass the value of it to the underlying component being rendered.
  • The component that we rendered previously was a stateless function that returned either the LoginRegisterForm or the Main component. Neither of these received any parameters or properties from React Router. Now, however, it is required that all properties of React Router are transferred to the child component. That includes the username parameter that we just introduced. We use the same destructuring assignment with the props object to pass all properties to the User component.

Those are all of the changes that we need to accept parameterized paths in React Router. We read out the value inside of the new user page component. Before implementing it, we import the dependency at the top of router.js to get the preceding route working:

import User from './User';

Create the preceding User.js file next to the Main.js file. Like the Main component, we are collecting all of the components that we render on this page. You should stay with this layout, as you can directly see which main parts each page consists of. The User.js file should look as follows:

import React, { Component } from 'react';
import UserProfile from './components/user';
import Chats from './Chats';
import Bar from './components/bar';
import CurrentUserQuery from './components/queries/currentUser';

export default class User extends Component {
render() {
return (
<CurrentUserQuery>
<Bar changeLoginState={this.props.changeLoginState}/>
<UserProfile username={this.props.match.params.username}/>
<Chats />
</CurrentUserQuery>
);
}
}

Like before, we use the CurrentUserQuery component as a wrapper for the Bar component and the Chats component. If a user visits the profile of a friend, they see the common application bar at the top. They can access their chats on the right-hand side, like in Facebook. It is one of the many situations in which React and the reusability of components come in handy.

We removed the Feed component and replaced it with a new UserProfile component. Importantly, the UserProfile receives the username property. Its value is taken from the properties of the User component. These properties were passed over by React Router. If you have a parameter, such as a username, in the routing path, the value is stored in the match.params.username property of the child component. The match object generally contains all matching information of React Router.

From this point on, you can implement any custom logic that you want with this value. We will now continue with implementing the profile page.

Follow these steps to build the user's profile page:

  1. Create a new folder, called user, inside the components folder.
  2. Create a new file, called index.js, inside the user folder.
  3. Import the dependencies at the top of the file, as follows:
import React, { Component } from 'react';
import PostsQuery from '../queries/postsFeed';
import FeedList from '../post/feedlist';
import UserHeader from './header';
import UserQuery from '../queries/userQuery';

The first three lines should look familiar. The last two imported files, however, do not exist at the moment, but we are going to change that shortly. The first new file is UserHeader, which takes care of rendering the avatar image, the name, and information about the user. Logically, we request the data that we will display in this header through a new Apollo query, called UserQuery.

  1. Insert the code for the UserProfile component that we are building at the moment beneath the dependencies, as follows:
export default class UserProfile extends Component {
render() {
const query_variables = { page: 0, limit: 10, username:
this.props.username };
return (
<div className="user">
<div className="inner">
<UserQuery variables={{username: this.props.username}}>
<UserHeader/>
</UserQuery>
</div>
<div className="container">
<PostsQuery variables={query_variables}>
<FeedList/>
</PostsQuery>
</div>
</div>
)
}
}

The UserProfile class is not complex. We are running two Apollo queries simultaneously. Both have the variables property set. The PostQuery receives the regular pagination fields, page and limit, but also the username, which initially came from React Router. This property is also handed over to the UserQueryinside of a variables object.

  1. We should now edit and create the Apollo queries, before programming the profile header component. Open the postsFeed.js file from the queries folder.

To use the username as input to the GraphQL query we first have to change the query string from the GET_POSTS variable. Change the first two lines to match the following code:

query postsFeed($page: Int, $limit: Int, $username: String) { 
postsFeed(page: $page, limit: $limit, username: $username) {

Add a new line to the getVariables method, above the return statement:

if(typeof variables.username !== typeof undefined) {
query_variables.username = variables.username;
}

If the custom query component receives a username property, it is included in the GraphQL request. It is used to filter posts by the specific user that we are viewing.

  1. Create a new userQuery.js file in the queries folder to create the missing query class.
  2. Import all of the dependencies and parse the new query schema with graphl-tag, as follows:
import React, { Component } from 'react';
import { Query } from 'react-apollo';
import Loading from '../loading';
import Error from '../error';
import gql from 'graphql-tag';

const GET_USER = gql`
query user($username: String!) {
user(username: $username) {
id
email
username
avatar
}
}
`;

The preceding query is nearly the same as the currentUser query. We are going to implement the corresponding user query later, in our GraphQL API.

  1. The component itself is as simple as the ones that we created before. Insert the following code:
export default class UserQuery extends Component {
getVariables() {
const { variables } = this.props;
var query_variables = {};
if(typeof variables.username !== typeof undefined) {
query_variables.username = variables.username;
}
return query_variables;
}
render() {
const { children } = this.props;
const variables = this.getVariables();
return(
<Query query={GET_USER} variables={variables}>
{({ loading, error, data }) => {
if (loading) return <Loading />;
if (error) return <Error><p>{error.message}</p></Error>;
const { user } = data;
return React.Children.map(children, function(child){
return React.cloneElement(child, { user });
})
}}
</Query>
)
}
}

We set the query property and the parameters that are collected by the getVariables method to the GraphQL Query component. The rest is the same as any other query component that we have written. All child components receive a new property, called user, which holds all the information about the user, such as their name, their email, and their avatar image. You can extend that later on, but always remember to not publish data that should be private.

  1. The last step is to implement the UserProfileHeader component. This component renders the user property, with all its values. It is just simple HTML markup. Copy the following code into the header.js file, in the user folder:
import React, { Component } from 'react';

export default class UserProfileHeader extends Component {
render() {
const { avatar, email, username } = this.props.user;
return (
<div className="profileHeader">
<div className="avatar">
<img src={avatar}/>
</div>
<div className="information">
<p>
{username}
</p>
<p>
{email}
</p>
<p>You can provide further information here and build
your really personal header component for your users.</p>
</div>
</div>
)
}
}

If you need help getting the CSS styling right, take a look at the official repository for this book. The preceding code only renders the user's data; you could also implement features such as a chat button, which would give the user the option to start messaging with other people. Currently, we have not implemented this feature anywhere, but it is not necessary to explain the principles of React and GraphQL.

We have finished the new front end components, but the UserProfile component is still not working. The queries that we are using here either do not accept the username parameter or have not yet been implemented.

The next section will cover which parts of the back end have to be adjusted.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.125.171