DEV Community

Cover image for React Project: HashTags for Posts with Auth — Part #2
Selva kumar
Selva kumar

Posted on

React Project: HashTags for Posts with Auth — Part #2

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 :

Alt Text

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;
Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode

To be continued Part-3

Top comments (0)