I can't find where the culprit is. I tried to debug it, but can't found what really make it those error:
cannot read properties of null (reading 'useContext') && react.development.js:209 Warning: 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:
- You might have mismatching versions of React and the renderer (such as React DOM)
- You might be breaking the Rules of Hooks
- You might have more than one copy of React in the same app
App.js
function App() {
return (
<React.Fragment>
<Counter/>
</React.Fragment>
);
}
export default App;
index.js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider context={StoreContext} store={Store()}>
<App />
</Provider>
);
reportWebVitals();
CounterReducer.js
const CounterReducer = (state = { count: 0 } , action) => {
switch (action.type) {
case handleDencrement:
return state.count - 1
case handleIncrement:
return state.count + 1
default:
return state
}
}
export default CounterReducer;
context.js
const StoreContext = React.createContext();
export default StoreContext ;
Store.js
const Store = () => {
const store = useStore(CounterReducer);
return store
}
export default Store;
types.js
export const handleIncrement = 'handleIncrement' ;
export const handleDencrement = 'handleDencrement';
Counter.js
const Counter = () => {
const [count, setcount] = useState(0);
const handleIncrement = () => {
setcount(count + 1);
}
const handleDencrement = () => {
setcount(count - 1);
}
return (
<div>
<center>
<h1>Redux</h1>
<h1>{count}</h1>
<button className="btn btn-primary" onClick={handleIncrement}>Increment</button>
<button className="btn btn-warning" onClick={handleDencrement}>decrement</button>
</center>
</div>
);
}
export default Counter;
My issue was solved with Next.js by just stopping the server using 'Ctrl + C'. And restarted the server using 'npm run dev'. Hope this helps.
Store
isn't a React component so it can't use the useStore
hook.
useStore
This hook returns a reference to the same Redux store that was passed in to the
<Provider>
component.
In other words, the useStore
hook is expecting a Redux Context to be provided to it from higher in the ReactTree.
From what I can tell of the code it seems you want the Store
function to create and return a Redux store object, to be passed to the Provider
component.
store.js
import { createStore, combineReducers } from 'redux';
import counter from '../path/to/counter.reducer';
const rootReducer = combineReducers({
counter,
});
const store = createStore(rootReducer);
export default store;
types
export const handleIncrement = 'handleIncrement' ;
export const handleDecrement = 'handleDecrement';
counter.reducer.js
The reducer function should maintain the state invariant. In this case the state is an object with a count
property.
const counterReducer = (state = { count: 0 }, action) => {
switch (action.type) {
case handleDecrement:
return {
...state,
count: state.count - 1
};
case handleIncrement:
return {
...state,
count: state.count + 1,
};
default:
return state;
}
};
index.js
...
import store from '../path/to/store';
...
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);
Counter
Instead of using local component state the component should use the useSelector
and useDispatch
hooks to read and update the counter
state in the store.
import { useDispatch, useSelector } from 'react-redux';
const Counter = () => {
const dispatch = useDispatch();
const count = useSelector(state => state.counter.count);
const handleIncrement = () => {
dispatch({ type: handleIncrement });
}
const handleDecrement = () => {
dispatch({ type: handleDecrement });
}
return (
<div>
<center>
<h1>Redux</h1>
<h1>{count}</h1>
<button className="btn btn-primary" onClick={handleIncrement}>Increment</button>
<button className="btn btn-warning" onClick={handleDecrement}>decrement</button>
</center>
</div>
);
}
export default Counter;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With