ZK.Wang
ZK.Wang

Reputation: 50

Error: Invalid Hook call on component list map. ReactJS

In Review components, I want to use hooks and got error below.
In fact I use YhSection to manage my parallel components, and use array map to put them in layout content.
I find if I use hooks out of

{yhSection.map((section) => (
    <Route key={section.key} path={section.path}>
      {section.components}
    </Route>
))}

, it works, but in , it doesn't.
hooks call error is in Review.tsx

I'll really appreciate your help.


Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app

MyContentWithRoute.tsx

import React, { FC } from 'react';
import { Route, Switch } from 'react-router-dom';
import { Layout } from 'antd';
import My404 from './My404';

import yhSection from './YhSection';

const MyContentWithRoute: FC = () => (
  <Layout.Content style={{ margin: '16px', background: '#fff' }}>
    <Switch>
      {yhSection.map((section) => (
        <Route key={section.key} path={section.path}>
          {section.components}
        </Route>
      ))}
      <Route path="*">
        <My404 />
      </Route>
    </Switch>
  </Layout.Content>
);

export default MyContentWithRoute;

YhSection.tsx

import { FC } from 'react';

import Review from './Review';
import Profit from './Profit';
import Policy from './Policy';
import Fluid from './Fluid';
import Capital from './Capital';
import Risk from './Risk';
import Trader from './Trader';
import Valuation from './Valuation';

interface YhSection {
  key: string;
  name: string;
  path: string;
  components: FC;
}

const yhSection: YhSection[] = [
  { key: 'review', path: '/review', components: Review },
  { key: 'profit', path: '/profit', components: Profit },
  { key: 'policy', path: '/policy', components: Policy },
  { key: 'fluid', path: '/fluid', components: Fluid },
  { key: 'capital', path: '/capital', components: Capital },
  { key: 'risk', path: '/risk', components: Risk },
  { key: 'trader', path: '/trader', components: Trader },
  { key: 'valuation', path: '/valuation', components: Valuation },
];

export default yhSection;

Review.tsx

import React, { useState } from 'react';
import Chart from './Chart';

const Review: React.FC = () => {
  const [state, setState] = useState(2);
  const data1 = [
    { date: '1991', value: 3 },
    { date: '1992', value: 4 },
    { date: '1993', value: 3.5 },
    { date: '1994', value: 5 },
    { date: '1995', value: 4.9 },
    { date: '1996', value: 6 },
    { date: '1997', value: 7 },
    { date: '1998', value: 9 },
    { date: '1999', value: 13 },
  ];
  console.log(state);
  return <Chart data={data1} />;
};

export default Review;

package.json

{
  "name": "vmp_frontend",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@ant-design/charts": "^0.9.6",
    "@craco/craco": "^5.6.4",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.5.0",
    "@testing-library/user-event": "^7.2.1",
    "@types/jest": "^24.9.1",
    "@types/node": "^12.12.47",
    "@types/react": "^16.9.36",
    "@types/react-dom": "^16.9.8",
    "@types/react-router-dom": "^5.1.5",
    "ahooks": "^2.0.1",
    "antd": "^4.3.4",
    "axios": "^0.19.2",
    "craco-less": "^1.17.0",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-router-dom": "^5.2.0",
    "react-scripts": "3.4.1",
    "typescript": "^3.7.5"
  },
  "scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test",
    "eject": "craco eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^3.3.0",
    "@typescript-eslint/parser": "^3.3.0",
    "eslint": "^6.8.0",
    "eslint-config-prettier": "^6.11.0",
    "eslint-plugin-prettier": "^3.1.4",
    "eslint-plugin-react": "^7.20.0",
    "eslint-plugin-react-hooks": "^4.0.4",
    "prettier": "^2.0.5"
  }
}

Upvotes: 1

Views: 591

Answers (2)

HMR
HMR

Reputation: 39280

Try the following

<Route 
  key={section.key}
  path={section.path}
  component={section.components} 
/>

Upvotes: 1

Rostyslav
Rostyslav

Reputation: 2866

It seems that you are trying to render a component function instead of component JSX instance. Just look at this:

{ key: 'review', path: '/review', components: Review }, // here Review is component function
{yhSection.map((section) => (
    <Route key={section.key} path={section.path}>
      {/* here it is still a component function not a JSX element (it is Review and not <Review /> or React.createElement(Review) */}
      {section.components}
    </Route>
))}

Try to pass the component function directly into Route as parameter:

{yhSection.map((section) => (
  <Route key={section.key} path={section.path} component={section.components} />
))}

Upvotes: 3

Related Questions