简体   繁体   中英

React get state from Redux store within useEffect

What is the correct way to get state from the Redux store within the useEffect hook?

    useEffect(() => { 
        const user = useSelector(state => state.user);
    });

I am attempting to get the current state within useEffect but I cannot use the useSelector call because this results in an error stating:

Invariant Violation: Hooks can only be called inside the body of a function component.

I think I understand why as it breaks one of the primary rules of hooks.

From reviewing the example on the Redux docs they seem to use a selectors.js file to gather the current state but this reference the mapStateToProps which I understood was no longer necessary.

Do I need to create some kind of "getter" function which should be called within the useEffect hook?

Don't forget to add user as a dependency to useEffect otherwise your effect won't get updated value.

const user = useSelector(state => state.user);
useEffect(() => { 
   // do stuff     
}, [user]);

You can place useSelector at the top of your component along with the other hooks:

const MyComponent = () => {
  ...
  const user = useSelector(state => state.user);
  ...
}

Then you can access user inside your useEffect s.

I found using two useEffects to works for me, and have useState to update the user (or in this case, currUser).

const user = useSelector(state=>state.user);
const [currUser, setCurrUser] = useState(user);

useEffect(()=>{
  dispatch(loadUser());
}, [dispatch]);

useEffect(()=>{
  setCurrUser(user);
}, [user]);

You have to use currUser to display and manipulate that object.

You have two choices.

1 - If you only need the value from store once or 'n' time your useEffect is called and don't want to listen for any changes that may occur to user state from redux then use this approach

//import the main store file from where you've used createStore()
import {store} from './store' // this will give you access to redux store

export default function MyComponent(){
   useEffect(() =>{
      const user = store.getState().user;
      //... 
   },[])
}

2 - If you want to listen to the changes that may occur to user state then the recommended answer is the way to go about

const MyComponent = () => {
 //...
  const user = useSelector(state => state.user);
  
  useEffect(() => {
    //...
  },[])
 //...
}
const tournamentinfofromstore=useSelector(state=>state.tournamentinfo)
useEffect(() => {
console.log(tournamentinfofromstore)
}, [tournamentinfofromstore])

So the problem is that if you change the state inside the useEffect that causes a rerender and then again the useEffect gets called "&&" if that component is passing data to another component will result in infinite loops.and because you are also storing that data in the child component's state will result in rerendering and the result will be infinite loop.!!

To add on top of @Motomoto's reply. Sometimes you depend on store to be loaded before useEffect. In this case you can simply return in if the state is undefined. useEffect will rerender once the store is loaded

const user = useSelector(state => state.user);

useEffect(() => {
  if(user === undefined){
    return}else{ 
    // do stuff
}}, [user]);

I'm having the same issue, The problem to the useSelector is that we cant call it into the hook, so I can't be able to update with the action properly. so I used the useSelector variable as a dependency to the useEffect and it solved my problem.

const finalImgData_to_be_assigned = useSelector((state) => state.userSelectedImg);
useEffect(()=>{
console.log('final data to be ready to assign tags : ', finalImgData_to_be_assigned.data);
}, [finalImgData_to_be_assigned ])

Although it is not recommended, you can use store directly in your component, even in the useEffect .

First, you have to export store from where it is created.

import invoiceReducer from './slices/invoiceSlice';
import authReducer from './slices/authSlice';

export const store = configureStore({
  reducer: {
    invoices: invoicesReducer,
    auth: authReducer,
  },
});

Then you can import it to a React Component , or even to a function , and use it.

import React, { useEffect } from 'react';
import { store } from './store';

const MyComponent = () => {
  useEffect(()=> {
    const invoiceList = store.getState().invoices
    console.log(invoiceList)
  }, [])

  return (
    <div>
      <h1>Hello World!</h1>
    </div>
  )
}

export default MyComponent
  • You can study the API for Store in here .
  • You can also see why this approach is not recommended in here .
  • Or, if you are interested in using redux store outside a react component , take a look at this blog post .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM