1

I'm a bit new to hooks, and I'm using a pattern I don't know is desirable or not. What I'm doing is mixing redux with useEffect hooks in a way that for every meaningful state change one of my hooks is triggered and update some state.

For example If I have a error field in my reducer. I write something like this.

useEffect(() => {
    if(state.error && !state.error.open) {
      showSnackbar(state.error.text)
    }
}, [state.error])

and I clear error when user dismiss snackbar.

Or

If I want to react to a button click with some data fetching and changing page I use:

(The reason I'm explicitly setting user clicked is when user clicks on back button in the next page, I'm not redirected to the page again as data is still present in store.)

useEffect(() => {
   if(buttonClicked && state.someData.id > 0) {
    history.push('/route');
}
}, [state.someData, buttonClicked]);


handleClick = () => {
    dispatch(actions.fetchSomeData());
    setUserClicked();
}

In my component sometimes I have 7-8 useEffects handling different things, and most of them have conditional behavior.

Lots of the time I see code like this:

const result = await dispatch(someAction);
if (result.payload.error)
{
 //...
}
else
{
 history.push(...);
}

Does this pattern have some advantage over using multiple lifecycle hooks?

Maybe I use the first way beacuse it feels more declarative? But is it good to have many useEffects? In the above code I handled error and success in two hooks.

Thanks.

3
  • You can use pretty much as many effects as your component needs. I also think using preventDefault on the button onClick event may help you. The second pattern is something I see used more with asynchronous redux actions, like API calls to fetch data, usually with middleware like Thunks (redux-thunk), but this is usually to allow returning errors directly back to the UI while having the request fetching/processing logic decoupled from the component code. Commented Apr 14, 2020 at 0:52
  • I use preventDefault but I removed those parts for the sake of brevity. and my main use case of useEffects is for doing some action in response to state changes whether async or sync. and most of the time they are in my containers not components. I mean instead of awaiting async action to get response and use that response to fire another action, I hook an event listener (useEffect) to that specific data and when it gets populated I fire another action. Is it ok? Commented Apr 14, 2020 at 9:29
  • 1
    Sure. That's what effects are for; any changes to values in their dependency array triggers them to run their side-effect callback. Commented Apr 14, 2020 at 15:14

1 Answer 1

1

If you write too many useEffect, it is an implicit indicator that your components are too big. You should start looking into creating smaller functional / stateless components (not necessary rendering any markup). Several pages of code per component is max size for well structured code. Update: here is code without effect:

if(buttonClicked && state.someData.id > 0) {
    return <Redirect to="/route" />
}

handleClick = () => {
    dispatch(actions.fetchSomeData());
    setUserClicked();
}
Sign up to request clarification or add additional context in comments.

2 Comments

Checked my code right now. I have 10 useEffects maximum in one file and maximum size of my code in one component is about 300-350 lines. I think it should be ok based on your answer? My concern was that using useEffect for this kind of tasks to be inappropriate.
If you get rid of useEffect and just have regular if check before render it should work fine: ` if(buttonClicked && state.someData.id > 0) { return <Redirect to="/route" /> } ` You may be using effects where you dont really need them.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.