Reputation: 7672
Google's lighthouse tool gave my app an appalling performance score so I've been doing some investigating. I have a component called Home
inside Home
I have useEffect (only one) that looks like this
useEffect(() => {
console.log('rendering in here?') // called 14 times...what?!
console.log(user.data, 'uvv') // called 13 times...again, What the heck?
}, [user.data])
I know that you put the second argument of , []
to make sure useEffect
is only called once the data changes but this is the main part I don't get. when I console log user.data
the first 4 console logs are empty arrays. the next 9 are arrays of length 9. so in my head, it should only have called it twice? once for []
and once for [].length(9)
so what on earth is going on?
I seriously need to reduce it as it must be killing my performance. let me know if there's anything else I can do to dramatically reduce these calls
this is how I get user.data
const Home = ({ ui, user }) => {
// I pass it in here as a prop
const mapState = ({ user }) => ({
user,
})
and then my component is connected so I just pass it in here
Upvotes: 2
Views: 968
Reputation: 39320
This is not an answer but there is too much code to fit in a comment. First you can log all actions that change user.data by replacing original root reducer temporarlily:
let lastData = {};
const logRootReducer = (state, action) => {
const newState = rootReducer(state, action);
if (newState.user.data !== lastData) {
console.log(
'action changed data:',
action,
newState.user.data,
lastData
);
lastData = newState.user.data;
}
return newState;
};
Another thing causing user.data to keep changing is when you do something like this in the reducer:
if (action.type === SOME_TYPE) {
return {
...state,
user: {
...state.user,
//here data is set to a new array every time
data: [],
},
};
}
Instead you can do something like this:
const EMPTY_DATA = [];
//... other code
data: EMPTY_DATA,
Your selector is getting user
out of state and creating a new object that would cause the component to re render but the dependency of the effect is user.data so the effect will only run if data actually changed.
Redux devtools also show differences in the wrong way, if you mutate something in state the devtools will show them as changes but React won't see them as changes. When you assign a new object to something data:[]
then redux won't show them as changes but React will see it as a change.
Upvotes: 1
Reputation: 642
To overcome this scenario, React Hooks also provides functionality called useMemo. You can use useMemo instead useEffect because useMemo cache the instance it renders and whenever it hit for render, it first check into cache to whether any related instance has been available for given deps.. If so, then rather than run entire function it will simply return it from cache.
Upvotes: 1