Category/index.js: import React, { useEffect, useState } from 'react'; import { Col, Container, Row} from 'react-bootstrap'; import { useDispatch, useSelector } from 'react-redux'; import { addCategory, getAllCategory } from '../../actions/category.action'; import Layout from '../../components/Layout'; import Input from '../../components/UI/Input'; import Modal from '../../components/UI/Modal'; import CheckboxTree from 'react-checkbox-tree'; import 'react-checkbox-tree/lib/react-checkbox-tree.css'; const Category = (props) => { const category = useSelector(state => state.category); const [categoryName, setCategoryName] = useState(''); const [show, setShow] = useState(false); const dispatch = useDispatch(); const [checked, setChecked] = useState([]); const [expanded, setExpanded] = useState([]); const handleClose = () => { const cat = { categoryName }; dispatch(addCategory(cat)); setShow(false); } const handleShow = () => setShow(true); const renderCategories = (categories) => { let myCategories = []; for (let category of categories) { myCategories.push( <li key={category.name}> {category.name} {category.children.length > 0 ? (<ul>renderCategories(category.children)</ul>): null} </li> ); } return myCategories; } const createCategoryList = (categories, options = []) => { for (let category of categories) { options.push({ value: category._id, name: category.name }); if (category.children.length > 0) { createCategoryList(category.children, options) } } return options; } return ( <Layout sidebar> <Container> <Row> <Col md={12}> <div style={{ display: 'flex', justifyContent: 'space-around' }}> <h3> Category </h3> <button onClick={handleShow}>Add</button> </div> </Col> </Row> <Row> <Col md={12}> <ul> {renderCategories(category.categories)} </ul> </Col> </Row> </Container> <Modal show={show} handleClose={handleClose} modalTitle={"Add New Category"} > <Input type="text" value={categoryName} placeholder={'Category Name'} onChange={(e) => setCategoryName(e.target.value)} /> </Modal> </Layout> ) } export default Category actions/category.action.js import axios from '../helpers/axios'; import { categoryConstants } from './constants'; export const getAllCategory = () => { return async dispatch => { dispatch({ type: categoryConstants.GET_ALL_CATEGORIES_REQUEST }); const res = await axios.get('category/getcategory'); console.log(res); if (res.status === 200) { const { categoryList } = res.data; dispatch({ type: categoryConstants.GET_ALL_CATEGORIES_SUCCESS, payload: { categories: categoryList } }); } else { dispatch({ type: categoryConstants.GET_ALL_CATEGORIES_FAILURE, payload: { error: res.data.error } }); } } } export const addCategory = (cat) => { return async dispatch => { dispatch({ type: categoryConstants.ADD_NEW_CATEGORY_REQUEST }); try { const res = await axios.post('/category/create', cat); if (res.status === 201) { dispatch({ type: categoryConstants.ADD_NEW_CATEGORY_SUCCESS, payload: { category: res.data.category } }); } else { dispatch({ type: categoryConstants.ADD_NEW_CATEGORY_FAILURE, payload: res.data.error }); } } catch(error) { console.log(error.response); } } } reducers/category.reducer.js import { categoryConstants } from "../actions/constants"; const initState = { categories: [], loading: false, error: null }; const buildNewCategories = (parentId, categories, category) => { let myCategories=[]; if(parentId == undefined){ return [ ...categories, { _id: category._id, name: category.name, slug: category.slug, children: [] } ]; } for(let cat of categories){ if (cat._id == parentId) { myCategories.push({ ...cat, children: cat.children ? buildNewCategories(parentId, [...cat.children, { _id: category._id, name: category.name, slug: category.slug, parentId: category.parentId, children: category.children }], category): [] }); }else{ myCategories.push({ ...cat, children: cat.children ? buildNewCategories(parentId, cat.children, category): [] }); } } return myCategories; } export default (state = initState, action) => { switch (action.type){ case categoryConstants.GET_ALL_CATEGORIES_SUCCESS: state = { ...state, categories: action.payload.categories } break; case categoryConstants.ADD_NEW_CATEGORY_REQUEST: state = { ...state, loading: true } break; case categoryConstants.ADD_NEW_CATEGORY_SUCCESS: const category = action.payload.category; const updatedCategories = buildNewCategories(category.parentId, state.categories, category); console.log(updatedCategories); state = { ...state, categories: updatedCategories, loading: false } break; case categoryConstants.ADD_NEW_CATEGORY_FAILURE: state = { ...initState } break; } return state; }