Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix cannot read properties of null (reading 'useContext')?

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:

  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

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;
like image 768
Djamel Eddine Avatar asked Sep 05 '25 03:09

Djamel Eddine


2 Answers

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.

like image 85
Ganesh J Avatar answered Sep 07 '25 21:09

Ganesh J


Issue

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.

Solution

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;
like image 24
Drew Reese Avatar answered Sep 07 '25 19:09

Drew Reese



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!