LoginSignup
0
0

エラー解消:Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

Posted at

エラー文

Uncaught 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

翻訳
捕捉されないエラー: 無効なフック呼び出しです。フックはファンクション・コンポーネントのボディの内部でのみ呼び出すことができます。これは、以下のいずれかの理由で発生する可能性があります:

  1. Reactとレンダラー(React DOMなど)のバージョンが不一致である。
  2. フックのルールを破っている可能性がある。
  3. 同じアプリに複数のReactコピーがあるかもしれない。

予想

  1. Reactとレンダラー(React DOMなど)のバージョンが不一致である。
    →他の箇所でエラーしていないし、可能性は低い。
  2. フックのルールを破っている可能性がある。
    →可能性あり。
  3. 同じアプリに複数のReactコピーがあるかもしれない。
    →ない。

これらから、hooks の使い方を間違えている?

コード

関係ありそうなコードは下記。

templates/TodoCreateTemplate/index.jsx
/**
 * TodoTemplate
 *
 * @package components
 */
import { useTodoContext } from '../../../contexts/TodoContext';
import { InputForm } from '../../atoms/InputForm';
import { TextAreaForm } from '../../atoms/TextAreaForm';
import { CommonButton } from '../../atoms/CommonButton';
import { useTodoCreateTemplate } from './useTodoCreateTemplate';
import styles from './styles.module.css';

export const TodoCreateTemplate = () => {
  const { addTodo } = useTodoContext();
  const [
    { inputTitle, inputContent },
    { handleChangeTitle, handleChangeContent, handleCreateTodo },
  ] = useTodoCreateTemplate({ addTodo });

  /**
   * TodoTemplate
   * @returns {JSX.Element}
   * @constructor
   */
  return (
    <div className={styles.container}>
      <div className={styles.titleBox}>
        <h2>Create Todo</h2>
      </div>

      <form onSubmit={handleCreateTodo}>
        <InputForm inputVal={inputTitle} placeholder={'Title'} onChange={handleChangeTitle} />

        <TextAreaForm
          inputVal={inputContent}
          placeholder={'Content'}
          onChange={handleChangeContent}
        />

        <CommonButton label={'Create Todo'} type={'submit'} />
      </form>
    </div>
  );
};
templates/TodoCreateTemplate/useTodoCreateTemplate.js
/**
 * useTodoCreateTemplate
 *
 * @package hooks
 */
import { useState, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { TODO_PATH } from '../../../constants/pagenations';

~~~

  /**
   * Todo の新規登録処理
   * @type {function(*): void |*}
   */
  const handleCreateTodo = useCallback(
    () => {
      if (inputTitle && inputContent) {
        addTodo(inputTitle, inputContent);
        useNavigate(TODO_PATH.TOP);
      }
    },
    // これらが更新された時のみ、関数を再生成する
    [addTodo, inputTitle, inputContent, navigate],
  );
  
~~~
};
/hooks/useTodo.js
import { useState, useMemo, useCallback } from 'react';
import { INIT_TODO_LIST } from '../constants/data';

~~~

export const useTodo = () => {

~~~

  /**
   * Todo 新規登録処理
   * @param {*} e
   */
  const addTodo = useCallback((title, content) => {
    const newId = originTodoList.length + 1;
    const newTodo = {
      id: newId,
      title: title,
      content: content,
    };
    setOriginTodoList([...originTodoList, newTodo]);
    console.log(originTodoList);
  });
  
~~~
};

試したこと

  • hooks/useTodo.js の処理をコメントアウトしてもエラー解消しない。
  • TodoCreateTemplate/index.jsx はインポートして使用しているだけなので、原因である可能性は低いか。

TodoCreateTemplate/useTodoCreateTemplate.jsが原因か?

https://qiita.com/tatsumin0206/items/4e1076e2deedf20a9485
の、ルール① フックはトップレベルでしか呼び出せない が当てはまるような気がする。

解決

原因は、

templates/TodoCreateTemplate/useTodoCreateTemplate.js
/**
 * useTodoCreateTemplate
 *
 * @package hooks
 */
import { useState, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { TODO_PATH } from '../../../constants/pagenations';

~~~

  /**
   * Todo の新規登録処理
   * @type {function(*): void |*}
   */
  const handleCreateTodo = useCallback(
    () => {
      if (inputTitle && inputContent) {
        addTodo(inputTitle, inputContent);
        useNavigate(TODO_PATH.TOP);
      }
    },
    // これらが更新された時のみ、関数を再生成する
    [addTodo, inputTitle, inputContent, navigate],
  );
  
~~~
};

の、 useNavigate(TODO_PATH.TOP); だった。

templates/TodoCreateTemplate/useTodoCreateTemplate.js
  const handleCreateTodo = useCallback(
    () => {
      if (inputTitle && inputContent) {
        addTodo(inputTitle, inputContent);
        useNavigate(TODO_PATH.TOP);
        これ
      }
    },
};
templates/TodoCreateTemplate/useTodoCreateTemplate.js
  const navigate = useNavigate();
  
  const handleCreateTodo = useCallback(
    () => {
      if (inputTitle && inputContent) {
        addTodo(inputTitle, inputContent);
        navigate(TODO_PATH.TOP);
      }
    },
};

とすることで解決。お作法的なことだろうか…?

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0