javascript - 无效的钩子(Hook)调用错误react-redux钩子(Hook)

标签 javascript reactjs redux react-redux react-hooks

我是react-redux新手,我有一个问题。我查了很多网站,但无法解决这个错误。

错误文本在这里:

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

这是我的index.js 文件:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {Provider} from 'react-redux';
import { createStore } from 'redux'
import all from './reducers/index'

const store = createStore(all)
ReactDOM.render(
  <React.StrictMode>
    <Provider store ={store}>
    <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

reportWebVitals();

这是我的 ../reducers/index.js 文件:

import {
  combineReducers
} from "redux";
import TodoReducer from "./TodoReducer";
import filterReducer from "./filterReducer";

const all = combineReducers({
  TodoReducer,
  filterReducer,
});

export default all;

filterReducer.js

    import { SHOW_ALL, VISIBILITY_FILTER } from "../actions/actionTypes"; 
    
    const filterReducer = (state = SHOW_ALL, action) => {
      switch (action.type) {
        case "VISIBILITY_FILTER":
          return action.filter;
        default:
          return state;
      }
    };
    
    export default filterReducer;

TodoReducer.js

 import { ADD_TODO, DELETE_TODO, TOGGLE_TODO } from "../actions/actionTypes";
    
    const TodoReducer = (state = [], action) => {
      switch (action.type) {
        case "ADD_TODO":
          return [
            ...state, //todos
            {
              id: action.id,
              text: action.text,
              completed: false,
            },
          ];
    
        case "TOGGLE_TODO":
          return state.map((todo) =>
            todo.id === action.id
              ? {
                  ...todo,
                  completed: !todo.completed,
                }
              : todo
          );
    
        case "DELETE_TODO":
          const numIndex = parseInt(action.id);
          return state.filter((todo) => todo.id !== numIndex);
        default:
          return state;
      }
    };
    
    export default TodoReducer;

actionTypes.js

export const ADD_TODO = 'ADD_TODO'
export const TOGGLE_TODO = 'TOGGLE_TODO'
export const DELETE_TODO = 'DELETE_TODO'
export const SHOW_ALL = 'SHOW_ALL'
export const VISIBILITY_FILTER = 'VISIBILITY_FILTER'

actions.js

import { ADD_TODO, DELETE_TODO, TOGGLE_TODO, VISIBILITY_FILTER } from './actionTypes'

let TodoId = 0

export const addTodo = text => ({
    type: ADD_TODO,
    id: TodoId++,
    text
})

export const deleteTodo = (id) => ({
    type: DELETE_TODO,
    id: id
})

export const toggleTodo = (id) => ({
    type: TOGGLE_TODO,
    id: id
})

export const visibility_filter = filter => ({
  type: VISIBILITY_FILTER,
  filter
})

这里是 Todos.js (这个文件是我使用钩子(Hook)的地方):

import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { addTodo } from "../actions/actions";

const Todos = () => {
  const todos = useSelector((state) => state.todos);

  const dispatch = useDispatch();

  const onAddTodo = () =>
    dispatch(
      addTodo(inputText),
      todos.map((todo) => <div key={todo.id}>{todo.text}</div>)
    );

  const [inputText, setInputText] = useState("");

  const inputTextHandler = (e) => {
    setInputText(e.target.value);
  };

  return (
    <div>
      <div className="form-group row">
        <div className="col-sm-10">
          <input
            onChange={inputTextHandler}
            value={inputText}
            type="text"
            className="form-control"
            id="inputEmail3"
            placeholder="add todo here"
          />
          <button
            type="button"
            onClick={() => setInputText("")}
            style={{ marginTop: "25px", marginRight: "15px" }}
            className="btn btn-danger"
          >
            Cancel
          </button>
          <button
            type="button"
            onClick={onAddTodo}
            style={{ marginTop: "25px" }}
            className="btn btn-success"
          >
            Add Todo
          </button>
        </div>
      </div>
    </div>
  );
};

export default Todos;

这是 App.js:

import React from "react";
import Table from './components/Table'; // this file is empty for now
import Todos from './components/Todos'

function App() {
  return (
    <div className="App">
        <div className="container" style={{ marginTop: "80px"}} >
          <div className="row">
            <div className="col-lg-10 offset-lg-2 col-md-10 col-sm-12 col-xs-12">
              <Todos />
            </div>
            <Table />
          </div>
        </div>
      </div>
  );
}

export default App;

这是错误代码:

   8 | import all from './reducers/index'
   9 | 
  10 | const store = createStore(all,)
> 11 | ReactDOM.render(
  12 |   <React.StrictMode>
  13 |     <Provider store ={store}>
  14 |     <App />

可能有数千个错误,我正在努力应对 React 和 Redux...

有什么问题吗?你能帮我吗?感谢您的关注。

最佳答案

首先,我想建议改用钩子(Hook)进行 redux,因为它们简化了一切。

您可以从 react-redux 导入 useDispatchuseSelector 并使用它们(钩子(Hook)),而不是 connect访问和改变你的 redux 状态。

例如


import { useSelector, useDispatch } from "react-redux"

import { addTodo } from "../actions/actions"

export const Todo = () => {

  //accessing your list of todos
   const todos = useSelector(state => state.todos)
  
  //dispatching an action
  const dispatch = useDispatch()

   const onAddTodo = () => dispatch(addTodo(someData))


   return (
    <div>
      <div className="form-group row">
        <div className="col-sm-10">
          <input
            onChange={inputTextHandler}
            value={inputText}
            type="text"
            className="form-control"
            id="inputEmail3"
            placeholder="add todo here"
          />
          <button
            type="button"
            onClick={() => setinputText("")}
            style={{ marginTop: "25px", marginRight: "15px" }}
            className="btn btn-danger"
          >
            Cancel
          </button>
          <button
            type="button"
            onClick={onAddTodo}
            style={{ marginTop: "25px" }}
            className="btn btn-success"
          >
            Add Todo
          </button>
        </div>
      </div>
    </div>
  );
}

一般使用钩子(Hook)时,您需要了解一些事情,钩子(Hook)是在主组件内部声明的。

您不能在组件的另一个函数中声明钩子(Hook)。

例如

让我们使用上面的代码作为示例。 在上面的代码中,我们定义了 onAddTodo 函数,用于将操作分派(dispatch)到 redux 状态。 我们如何执行上面的代码是正确的,但在某些情况下我们可能会出错,而 React 当然会向我们抛出一个错误,就像您当前面临的错误一样。

下面是使用钩子(Hook)的错误方法,因为它是在不是主要组件的函数内声明或启动的。

const onAddTodo = () => {
   //WRONG...
   const dispatch = useDispatch()

   dispatch(addTodo(someData))
}

关于javascript - 无效的钩子(Hook)调用错误react-redux钩子(Hook),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68874142/

相关文章:

javascript - onClick 带参数的匿名函数 vs onClick(function(arguments))

unit-testing - 单元测试 React Bootstrap 模态对话框

angular - NgRx - 在路由器转换期间正在分派(dispatch)多个操作

javascript - 使用 redux 工具包时出现错误 "A non-serializable value was detected in the state"- 但不是普通的 redux

javascript - 如何在正在使用的同一组件中访问mapStateToProps?

javascript - 用于使用 jquery 添加的内容中的链接的函数

javascript - 如何删除列表中的对象? Javascript nodejs 和下划线

javascript - 具有最小网络流量的进度条

javascript - 如何删除警告 "This will upload all files from [Folder]. Only do this if you trust this site."

javascript - 通过cloneElement reactjs传递forwardRef