Search code examples
javascriptreactjstypescriptobject

Uncaught Error:Objects are not valid as a React child (found: object with keys.If you meant to render a collection of children, use an array instead


i am trying to resolve this issue related to Objects are not valid as a react child . Below for Select admin i am passing all the bots name in select tag as options .

I was able to fetch all bots name . When i am trying to pass user list from those bots i am facing this issue , Note : user list is array of objects

Here's the code so far let me know where i am missing anything which shoots this error , it would help me in several ways :)

import React, { FC , useEffect, useState } from 'react'
import { useIntl } from 'react-intl'
import { KTCard, KTCardBody } from '../../../_metronic/helpers'
import { PageTitle } from '../../../_metronic/layout/core'
import ReactPaginate from 'react-paginate';
import moment from 'moment'
import { get_bots , get_followers  } from '../../utills/api_helper'

function Items({ currentItems }) {
//currentItems refers to array of objects.
  const intl = useIntl()

  return (
    <>
      <div className='table-responsive'>
        <table
          id='kt_table_users'
          className='table align-middle table-row-dashed fs-6 gy-5 dataTable no-footer'
        >
          <thead>
            <tr className='text-start text-muted fw-bolder fs-7 text-uppercase gs-0'>
              <td>id</td>
              <td>name</td>
              <td>referred by</td>
              <td>total referrals</td>
              <td>Tag</td>
              <td>Follow/unfollow</td>
              <td>Action</td>
          </tr>
          </thead>
          <tbody className='text-gray-600 fw-bold'>
            {currentItems.length ?
              currentItems &&
              currentItems.map((item, index) => (
                <tr key={index}>
                  <td>{item.referral_code}</td>
                  <td>{item.displayName}</td>
                  <td>{item.referral_parent === null ? "---" : item.referral_parent}</td>
                  <td>{item.referral_count}</td>
                  <td>{!item.tagName ? "---" : item.tagName}</td>
                  <td>{item.follower_event_type}</td>
                </tr>
              ))
              : (
                <tr>
                  <td colSpan={7}>
                    <div className='d-flex text-center w-100 align-content-center justify-content-center'>
                      No Records..
                    </div>
                  </td>
                </tr>
              )}
          </tbody>
        </table>
      </div>
    </>
  );
}

function Paginater({ items }) {
  const intl = useIntl()
  const [admin, setAdmin] = useState<string | undefined>()
  const [itemsPerPage, setItemsPerPage] = useState<number>(10)
  const [forcePage, setForcePage] = useState<number>(0)
  const [remountComponent, setRemountComponent] = useState(0);
  const [ userGroupList , setUserGroupList ] = useState([]);

  // Here we use item offsets; we could also use page offsets
  // following the API or data you're working with.
  const [itemOffset, setItemOffset] = useState(0);

  useEffect(() => {
    get_followers({bot_id:admin}).then((res) => {
      setUserGroupList(res.data.data)
    })
  }, [admin])
  // Simulate fetching items from another resources.
  // (This could be items from props; or items loaded in a local state
  // from an API endpoint with useEffect and useState)
  const endOffset = itemOffset + itemsPerPage;
  const showingItemsText = `Showing items from ${itemOffset + 1} to ${endOffset <= userGroupList.length ? endOffset : userGroupList.length}`;
  const currentItems = userGroupList.slice(itemOffset, endOffset);

  const pageCount = Math.ceil(userGroupList.length / itemsPerPage);

  // Invoke when user click to request another page.
  const handlePageClick = (event) => {
    const newOffset = (event.selected * itemsPerPage) % userGroupList.length;
    setItemOffset(newOffset);
  };


  return (
    <>
      <div className='border-0' >
        <div className='row'>
          <div className='col-lg-1'>
            <div className='col-lg-12 py-2'>
              <select className='form-select' onChange={(e) => { setItemOffset(0); setItemsPerPage(parseInt(e.target.value)); setForcePage(0); setRemountComponent(Math.random()); }}>
                <option value={10}>10</option>
                <option value={20}>20</option>
                <option value={50}>50</option>
              </select>
            </div>
          </div>
          {/* begin::Card toolbar */}
          <div className='col-lg-10'>
            <div className='row'>
              <div className='col-lg-3 py-2'>
                <select
                  className='form-select form-select-solid'
                  data-placeholder='Select Admin'
                  onChange={(e) => setAdmin(e.target.value)}
                  value={admin}
                  style={{ fontWeight: 200 }}
                >
                  <option value=''>Select Admin</option>
                  {
                    items.map((bots: any, index) => {
                      return (
                        <option key={index.toString()} value={bots._id}>{bots.displayName}</option>
                      )
                    })
                  }
                </select>
              </div>
              <div className='col-lg-3 py-2'>
                <button type='button' className='btn btn-primary ms-3' onClick={()=>{setAdmin("")}} >
                 Reset
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>
      <Items currentItems={currentItems} />
      <div className='row' key={remountComponent}>
        <div className='col-lg-6 d-flex align-items-center'>{showingItemsText}</div>
        <ReactPaginate
          nextLabel="next >"
          onPageChange={handlePageClick}
          pageRangeDisplayed={3}
          marginPagesDisplayed={2}
          pageCount={pageCount}
          previousLabel="< previous"
          pageClassName="page-item"
          pageLinkClassName="page-link"
          previousClassName="page-item"
          previousLinkClassName="page-link"
          nextClassName="page-item"
          nextLinkClassName="page-link"
          breakLabel="..."
          breakClassName="page-item"
          breakLinkClassName="page-link"
          containerClassName="col-lg-6 pagination justify-content-end"
          activeClassName="active"
          renderOnZeroPageCount={() => null}
          forcePage={forcePage}
        />
      </div>
    </>
  );
}


const UserList: FC = () => {

  const [ botList , setBotList ] = useState([]);
//Obtaining all bots and passing to PaginatedItems
  useEffect(() => {
    get_bots({}).then((res) => {
      setBotList(res.data.data);
    });
  }, [])
 

  return (
    <>
      <KTCard>
        <KTCardBody className='py-4'>
          <Paginater items={botList} />
        </KTCardBody>
      </KTCard>
    </>
  )
}

const UsersWrapper: FC = () => {
  return (
    <>
      <PageTitle breadcrumbs={[]}>Users</PageTitle>
      <UserList />
    </>
  )
}

export { UsersWrapper }

example data which i receive from api for obtaining all users in the selected bot:

[0]
created_at: "2022-01-13T07:09:29.480Z"
displayName: "test_name"
follower_event_type: "follow"
follower_id: "follower_id"
follower_mode: "active"
follower_replyToken: "token_id"
follower_type: "user"
referral_code: "ref_code"
referral_count: 0
referral_parent : null
__v: 0
_id : "some_id"

[1]
created_at: "2022-01-13T07:09:29.480Z"
displayName: "test_name"
follower_event_type: "follow"
follower_id: "follower_id"
follower_mode: "active"
follower_replyToken: "token_id"
follower_type: "user"
referral_code: "ref_code"
referral_count: 0
referral_parent : null
__v: 0
_id : "some_id"

....and so on

any help is appreciated , thanks!


Solution

  • I run your code and replaced the api call with static data, and it seems to work without errors, maybe you should debug what your api is returning

    import React, { useEffect, useState } from 'react'
    import PropTypes from 'prop-types'
    
    const Items = ({ currentItems }) => {
      return (
        <>
          <div className="table-responsive">
            <table
              id="kt_table_users"
              className="table align-middle table-row-dashed fs-6 gy-5 dataTable no-footer"
            >
              <thead>
                <tr className="text-start text-muted fw-bolder fs-7 text-uppercase gs-0">
                  <td>id</td>
                  <td>name</td>
                  <td>referred by</td>
                  <td>total referrals</td>
                  <td>Tag</td>
                  <td>Follow/unfollow</td>
                  <td>Action</td>
                </tr>
              </thead>
              <tbody className="text-gray-600 fw-bold">
                {currentItems.length ? (
                  currentItems &&
                  currentItems.map((item, index) => (
                    <tr key={index}>
                      <td>{item.referral_code}</td>
                      <td>{item.displayName}</td>
                      <td>{item.referral_parent === null ? '---' : item.referral_parent}</td>
                      <td>{item.referral_count}</td>
                      <td>{!item.tagName ? '---' : item.tagName}</td>
                      <td>{item.follower_event_type}</td>
                    </tr>
                  ))
                ) : (
                  <tr>
                    <td colSpan={7}>
                      <div className="d-flex text-center w-100 align-content-center justify-content-center">
                        No Records..
                      </div>
                    </td>
                  </tr>
                )}
              </tbody>
            </table>
          </div>
        </>
      )
    }
    Items.propTypes = { currentItems: PropTypes.array }
    
    const Paginater = ({ items }) => {
      const [admin, setAdmin] = useState()
      const [itemsPerPage, setItemsPerPage] = useState(10)
      const [forcePage, setForcePage] = useState(0)
      const [remountComponent, setRemountComponent] = useState(0)
      const [userGroupList, setUserGroupList] = useState([])
    
      // Here we use item offsets; we could also use page offsets
      // following the API or data you're working with.
      const [itemOffset, setItemOffset] = useState(0)
    
      useEffect(() => {
        setUserGroupList([
          {
            created_at: '2022-01-13T07:09:29.480Z',
            displayName: 'test_name',
            follower_event_type: 'follow',
            follower_id: 'follower_id',
            follower_mode: 'active',
            follower_replyToken: 'token_id',
            follower_type: 'user',
            referral_code: 'ref_code',
            referral_count: 0,
            referral_parent: null,
            __v: 0,
            _id: 'some_id',
          },
          {
            created_at: '2022-01-13T07:09:29.480Z',
            displayName: 'test_name',
            follower_event_type: 'follow',
            follower_id: 'follower_id',
            follower_mode: 'active',
            follower_replyToken: 'token_id',
            follower_type: 'user',
            referral_code: 'ref_code',
            referral_count: 0,
            referral_parent: null,
            __v: 0,
            _id: 'some_id',
          },
        ])
      }, [admin])
      // Simulate fetching items from another resources.
      // (This could be items from props; or items loaded in a local state
      // from an API endpoint with useEffect and useState)
      const endOffset = itemOffset + itemsPerPage
      const showingItemsText = `Showing items from ${itemOffset + 1} to ${
        endOffset <= userGroupList.length ? endOffset : userGroupList.length
      }`
      const currentItems = userGroupList.slice(itemOffset, endOffset)
    
      const pageCount = Math.ceil(userGroupList.length / itemsPerPage)
    
      // Invoke when user click to request another page.
      const handlePageClick = (event) => {
        const newOffset = (event.selected * itemsPerPage) % userGroupList.length
        setItemOffset(newOffset)
      }
    
      return (
        <>
          <div className="border-0">
            <div className="row">
              <div className="col-lg-1">
                <div className="col-lg-12 py-2">
                  <select
                    className="form-select"
                    onChange={(e) => {
                      setItemOffset(0)
                      setItemsPerPage(parseInt(e.target.value))
                      setForcePage(0)
                      setRemountComponent(Math.random())
                    }}
                  >
                    <option value={10}>10</option>
                    <option value={20}>20</option>
                    <option value={50}>50</option>
                  </select>
                </div>
              </div>
              {/* begin::Card toolbar */}
              <div className="col-lg-10">
                <div className="row">
                  <div className="col-lg-3 py-2">
                    <select
                      className="form-select form-select-solid"
                      data-placeholder="Select Admin"
                      onChange={(e) => setAdmin(e.target.value)}
                      value={admin}
                      style={{ fontWeight: 200 }}
                    >
                      <option value="">Select Admin</option>
                      {items.map((bots, index) => {
                        return (
                          <option key={index.toString()} value={bots._id}>
                            {bots.displayName}
                          </option>
                        )
                      })}
                    </select>
                  </div>
                  <div className="col-lg-3 py-2">
                    <button
                      type="button"
                      className="btn btn-primary ms-3"
                      onClick={() => {
                        setAdmin('')
                      }}
                    >
                      Reset
                    </button>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <Items currentItems={currentItems} />
          <div className="row" key={remountComponent}>
            <div className="col-lg-6 d-flex align-items-center">{showingItemsText}</div>
            {/* <ReactPaginate
              nextLabel="next >"
              onPageChange={handlePageClick}
              pageRangeDisplayed={3}
              marginPagesDisplayed={2}
              pageCount={pageCount}
              previousLabel="< previous"
              pageClassName="page-item"
              pageLinkClassName="page-link"
              previousClassName="page-item"
              previousLinkClassName="page-link"
              nextClassName="page-item"
              nextLinkClassName="page-link"
              breakLabel="..."
              breakClassName="page-item"
              breakLinkClassName="page-link"
              containerClassName="col-lg-6 pagination justify-content-end"
              activeClassName="active"
              renderOnZeroPageCount={() => null}
              forcePage={forcePage}
            /> */}
          </div>
        </>
      )
    }
    
    Paginater.propTypes = { items: PropTypes.array }
    
    const UserList = () => {
      const [botList, setBotList] = useState([])
      //Obtaining all bots and passing to PaginatedItems
      useEffect(() => {
        setBotList([
          {
            created_at: '2022-01-13T07:09:29.480Z',
            displayName: 'test_name',
            follower_event_type: 'follow',
            follower_id: 'follower_id',
            follower_mode: 'active',
            follower_replyToken: 'token_id',
            follower_type: 'user',
            referral_code: 'ref_code',
            referral_count: 0,
            referral_parent: null,
            __v: 0,
            _id: 'some_id',
          },
          {
            created_at: '2022-01-13T07:09:29.480Z',
            displayName: 'test_name',
            follower_event_type: 'follow',
            follower_id: 'follower_id',
            follower_mode: 'active',
            follower_replyToken: 'token_id',
            follower_type: 'user',
            referral_code: 'ref_code',
            referral_count: 0,
            referral_parent: null,
            __v: 0,
            _id: 'some_id',
          },
        ])
      }, [])
    
      return (
        <>
          <Paginater items={botList} />
        </>
      )
    }
    
    const UsersWrapper = () => {
      return (
        <>
          <UserList />
        </>
      )
    }
    
    export default UsersWrapper