Djamel Eddine
Djamel Eddine

Reputation: 281

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;

Upvotes: 28

Views: 176251

Answers (15)

MosimiDev
MosimiDev

Reputation: 1

I had the same problem and discovered I made a silly mistake by calling one of my hooks outside of the function body. For instance, in AccountScreen component, I called dispatch outside the function body. Fixing this made the error go away

const dispatch = useAppDispatch();
export default function AccountScreen(){
  return(
    <View >
      <Text>Account Screen</Text>
    </View>
  )
}

instead of

export default function AccountScreen(){
const dispatch = useAppDispatch();
return(
<View >
   <Text>Account Screen</Text>
</View>)}

Upvotes: 0

Ezen
Ezen

Reputation: 261

Had the same problem in a monorepo project. After a long debugging I figured out that I was using a fixed version of react in my package.json

"react": "18.2.0",
"react-dom": "18.2.0",

And the version was conflicting with the version installed in the shared node_modules. So to fix the problem, add the ^ before the version number to use any variant of your main react version 18.x.x.

So the solution was this:

"react": "^18.2.0",
"react-dom": "^18.2.0",

Hope this helps someone !

Upvotes: 1

Maninder Singh
Maninder Singh

Reputation: 485

It can happen due to many reason but if you are creating your own library and testing it locally. use npm pack avoid using npm link

npm link not able to differentiate between version of react and this happened use npm pack and then install the .tgz file

Upvotes: 3

ElektrikSpark
ElektrikSpark

Reputation: 633

My issue was upgrading to [email protected] from [email protected]. This is potentially due to having different react versions for an Expo and Next.js app in a Turborepo. Be careful when bumping versions!

Upvotes: 0

Bahadur Khan
Bahadur Khan

Reputation: 31

I was getting the same error on 'next build' (wasted too many hours for solution)

SOLUTION: In my package.json I edited my build command under scripts

"build": "set NODE_ENV=production & next build",

Then in terminal instead of next build I executed

npm run build

Boom!! No error

Upvotes: 2

Reza td
Reza td

Reputation: 11

i had this problem and solved it by changing the version of react-bootstrap in package.json file.

delete all your node_modules, change the version like this:

"react-bootstrap": "2.9.2",

and after that, install your project again.

Upvotes: 0

Guilherme Bragamonte
Guilherme Bragamonte

Reputation: 41

For me, the problem was that one of my dependencies was using a different version (greater) of react and react-dom.

To force my dependencies to use the same version as my main package.json file, i've used the resolutions feature from yarn: https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/

If you're using npm, take a look at https://docs.npmjs.com/cli/v9/configuring-npm/package-json#overrides

Upvotes: 3

Emon_cste 14
Emon_cste 14

Reputation: 31

I install one package outside of root folder. Then I removed the extra json file. Then I go to root folder by cd client command and install my package.then restart my project. worked!

Upvotes: 0

Deshan Manodya
Deshan Manodya

Reputation: 1

I have the same problem when I was using framer motion library the first time.

If you install any kind of library like npm install framer-motion, you should stay in your project directory, then the library should show up in on your package.json file.

That's the way you can get rid of the "can not read properties of null".

Upvotes: 0

June
June

Reputation: 1

Try to uninstall node-packages. or

include change directory command before installing any package if you are using new terminal everytime.

so it creates only one node-modules,package-lock.json and package.json for the entire project.

like this:

npx create-react-app projectname
cd addtocart
npm start

cd projectname
npm install react-bootstrap bootstrap –save

cd projectname
npm install @reduxjs/toolkit

cd projectname
npm install react-redux

it worked for me.

Upvotes: 0

sukaran gulati
sukaran gulati

Reputation: 61

This might help someone, therefore adding to the answers. I had the same problem and it was the result of a silly mistake. While installing react bootstrap, I did npm install in the parent folder instead of project folder itself. When I later did npm install in the project folder itself the error was gone.

It was silly, for real.

Upvotes: 1

BAT
BAT

Reputation: 1

I had this problem and the answer was that I accidentally installed the locked package again, deleted it and it ran

Upvotes: 0

Ganesh J
Ganesh J

Reputation: 271

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.

Upvotes: 21

Richa Kochar
Richa Kochar

Reputation: 17

Delete and Reinstall the npm modules , Using the command = npm install, you can install npm modules.

This will resolve the error.

Upvotes: -1

Drew Reese
Drew Reese

Reputation: 203323

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;

Upvotes: 4

Related Questions