React Project: HashTags for Posts with Auth β Part #2
Selva kumar
Posted on March 16, 2021
This is Part-2. This blog post will explain how to split ReactJS Components.
In case if you do not have any idea about the basics of ReactJs and how to start with it, you can refer to link
Quick links for our Part Series:
PART #1 - Introduction and Installation of ReactJS (This Post)
PART #2 - ReactJS split the UI by components Components (This Post)
PART #3 - React Query for remote data fetching instead of Redux thunk
PART #4 - Internationalization with i18next
PART #5 - Basics to Advanced Usage of styled-components
Keep in mind that if you get stuck on any step, refer to the Github repo
To find the completed project, Demo link
Components let you split the UI into independent, reusable pieces, and think about each piece in isolation
In React it's important to split the UI by components, so let's check how many components do we need :
As you can see, seven components are standing out:
- Header
- Filter
- NavBar
- Authors
- Posts
- Author Details
- On-Boarding Forms | Details
A question to ask when creating a component:
What my component should do ?! π€
State management β The component subscribes to the store
Data fetching β It gets the state from the store
UI presentation β It renders
Business logic β Itβs tied to the business logic of the application.
I Will explain one by one component.
Header Component
The header component is pretty simple, it contains the project title
import React from "react";
const Heading = ({ title }) => {
return (
<div className="col">
<h1>{title}</h1>
</div>
);
};
export default Heading;
Filter Component
The Filter component should:
- Filling input fields with a JSON Array
- Apply Filter
- Query the API with this filter
In order to save the state of our input, we will use in this component the custom hook.
import React from 'react';
import { useDispatch } from 'react-redux';
import useFilterHook from '../../hooks/useFilterHooks';
import { authorsFiltering } from './author-slice';
import { useTranslation } from "react-i18next";
const filterTypes = [
{
type: 'Radio',
default: 'mr',
selected: 'Mr',
list: [
{ label: 'All', value: 'All' },
{ label: 'Mr.', value: 'mr' },
{ label: 'Miss.', value: 'miss' },
],
optional: false,
queryParamKey: 'title',
placeholder: null,
title: 'title',
},
{
type: 'Text',
default: '',
selected: '',
list: [],
optional: false,
queryParamKey: 'firstName',
placeholder: 'Search by FirstName',
title: 'first_name',
},
{
type: 'Text',
default: '',
selected: '',
list: [],
optional: false,
queryParamKey: 'lastName',
placeholder: 'Search by LastName',
title: 'last_name',
},
{
type: 'Text',
default: '',
selected: '',
list: [],
optional: false,
queryParamKey: 'email',
placeholder: 'Search by Email',
title: 'Email',
},
];
const Filter = () => {
const dispatch = useDispatch();
const { t: translation } = useTranslation();
const filtering = () => {
dispatch(authorsFiltering({ search_keys: inputs }));
}
const {inputs, handleInputChange, handleSubmit} = useFilterHook({ }, filtering);
return (
<div>
<h4> {translation('filters')} </h4>
<form onSubmit={handleSubmit} autoComplete="off">
{filterTypes.map((filter) => (
<article className='card-group-item' key={`${filter.title}`}>
<header className='card-header'>
<h6 className='border-bottom border-3'>
{translation(filter.title)}
</h6>
</header>
<div className='card-body'>
{filter.type === 'Radio' ? (
filter.list.map((item) => (
<label className='form-check' key={`${item.label}`}>
<input
type='radio'
name={filter.queryParamKey}
value={item.value}
onChange={ handleInputChange}
/>
<span className='form-check-label'> {item.label}</span>
</label>
))
) : (
<input
className='form-check-input'
type='text'
name={filter.queryParamKey}
onChange={handleInputChange}
/>
)}
</div>
</article>
))}
<br />
<button type='submit' className='btn btn-primary left'>
{ translation('apply')}
</button>
</form>
</div>
);
};
Filter.displayName = 'Filter';
export default Filter;
Authors Component
The Authors component should:
- get Authors from dummyAPi using react Query
- Loop on this array and render list
import React, { useEffect, lazy } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useAuthors } from './authors-hooks';
import { authorSelector, authorsReceived } from './author-slice';
const AuthorListView = lazy(() => import('./author-listing-view'));
const NoResult = lazy(() => import('../../components/empty-list'));
const Loader = lazy(() => import('../../components/loader'));
const AuthorListing = () => {
const { authors, filters: authorFilter } = useSelector(authorSelector);
const dispatch = useDispatch();
const { data, isFetching } = useAuthors();
const renderStatus = data && data.data;
useEffect(() => {
if (renderStatus) {
dispatch(authorsReceived(data.data));
}
}, [renderStatus]); // eslint-disable-line react-hooks/exhaustive-deps
const authorItemList = authors.map((authorDetails) => {
return (
<AuthorListView
key={`${authorDetails.firstName}-${authorDetails.lastName}`}
user={authorDetails}
/>
);
});
const authorFilterView = Object.keys(authorFilter).map((filter) => {
return (
<button class="btn btn-secondary ml-4">{filter.toUpperCase()} <span class="badge">{ authorFilter[filter] } </span></button>
);
});
if (isFetching) {
return <Loader />;
}
return <div>
<div>{ authorFilterView }</div>
{authors.length ? authorItemList : <NoResult />}
</div>;
};
AuthorListing.displayName = 'AuthorsListing';
export default AuthorListing;
Posts Component
The Posts component should:
- get posts from dummyAPi using react Query
- Loop on this array and render list
import React, { lazy } from 'react';
import { usePosts } from './posts-hooks';
const PostListView = lazy(() => import('./post-listing-view'));
const NoResult = lazy(() => import('../../components/empty-list'));
const Loader = lazy(() => import('../../components/loader'));
const PostsListing = () => {
const { data, isFetching } = usePosts();
const posts = (data && data.data) || [];
const postItemList = posts.map((postDetails) => {
return <PostListView key={`${postDetails.text}`} post={postDetails} />;
});
if (isFetching) {
return <Loader />;
}
return <div>{posts.length ? postItemList : <NoResult />}</div>;
};
PostsListing.displayName = 'PostsListing';
export default PostsListing;
To be continued Part-3
Posted on March 16, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.