Invalid hook call error react-redux hooks

Im new in react-redux and I have a problem. I looked many sites but I cant solve this error.

The error text is here:

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

here is my index.js file:

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();

here is my ../reducers/index.js file:

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
})

here is the Todos.js (This file is where i use 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" 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;

here is the 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;

and here is the error code:

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

There may be thousands of mistakes, I'm struggling with react and redux so hard...

What is the problem? Can you help me please? Thank you for your attention.

6

2 Answers

After looking at your code, I saw this.

 <button type="button" onClick={(inputText = "")} style={{ marginTop: "25px", marginRight: "15px" }} className="btn btn-danger" >

The problem is with :

onClick={(inputText = "")}

The state of a component can be changed only with the function that is provided when you create the state. In your case that function is called setInputText.

Your button should look like this :

const handleInputReset = () => setInputText('');
<button type="button" onClick={handleInputReset} style={{ marginTop: "25px", marginRight: "15px" }} className="btn btn-danger" >

Reference :

3

First I will like to advice to switch to using hooks for redux as they simplify everything.

Instead of connect you can import useDispatch and useSelector from react-redux and use them (hooks) to access and mutate your redux state.

E.g

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" 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> );
}

When using hooks generally, there's something you need to understand, hooks are declared right inside the main component.

You can't declare a hook inside another function of the component.

E.g

Let's use the above code for our example. In the above code we defined onAddTodo function where we used to to dispatch an action to our redux state. How we do the above code is correct but there will be a situation where we can be wrong and react will of course throw us an error like the one you re currently facing.

Below is the wrong way of using hooks because it's been declared or initiated right inside a function that's not the main component.

const onAddTodo = () => { //WRONG... const dispatch = useDispatch() dispatch(addTodo(someData))
}
3

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like