Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does using React Hooks drastically reduce how code can be reused in React / Redux?

Tags:

reactjs

redux

Let's say we have the old traditional way of React / Redux: (you don't need to expand the code if you are familiar with it:)

import React from 'react';
import { connect } from 'react-redux';

function Count(props) {
  return (
    <div>
      <button onClick={props.increment}> + </button>
      {props.count}
      <button onClick={props.decrement}> - </button>
    </div>
  );
}

const mapStateToProps = state => ({
  count: state.count
});

const mapDispatchToProps = dispatch => ({
  increment: () => dispatch({ type: 'INCREMENT' }),
  decrement: () => dispatch({ type: 'DECREMENT' })
});

export default connect(mapStateToProps, mapDispatchToProps)(Count);

Now, using React Hooks useSelector() and useDispatch(), the above code could be written as this way:

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';

function Count() {
  const count = useSelector(state => state.count);
  const dispatch = useDispatch();

  const increment = () => dispatch({ type: 'INCREMENT' });
  const decrement = () => dispatch({ type: 'DECREMENT' });

  return (
    <div>
      <button onClick={increment}> + </button>
      {count}
      <button onClick={decrement}> - </button>
    </div>
  );
}

export default Count;

Both versions work exactly the same, by themselves, except, isn't version 1 highly reusable for Count? That's because using a different mapStateToProps() and mapDispatchToProps(), we can use connect() again to create another CountNoodle() and now we have reused Count().

For version 2, Count() is hard-wired with what state and dispatch it uses, so the whole Count() is entirely not-reusable. That is, it has to be used with that particular state and particular dispatch, but nothing else. Isn't it true? So is version 2 above not recommended and actually you would have a version 3, which is not to call it Count() but called it CountNoodle() and "wire up" the state and dispatch, and re-use Count(), which would be simply "presentational"?

So it may look something like this:

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';

// Count() actually would be in a different file and CountNoodle.js
//   would import that file
function Count({count, increment, decrement}) {
  return (
    <div>
      <button onClick={increment}> + </button>
      {count}
      <button onClick={decrement}> - </button>
    </div>
  );
}

function CountNoodle() {
  const count = useSelector(state => state.countNoodle);
  const dispatch = useDispatch();

  const increment = () => dispatch({ type: 'INCREMENT_NOODLE' });
  const decrement = () => dispatch({ type: 'DECREMENT_NOODLE' });

  return <Count ...{count, increment, decrement} />;
  // or   return Count({count, increment, decrement});
}

export default CountNoodle;
like image 296
nonopolarity Avatar asked Apr 21 '20 07:04

nonopolarity


People also ask

Is React Hooks better than Redux?

Redux vs. On the other hand, with React Hooks and the useContext API, there is no need to install external libraries or add a bunch of files and folders to make our app work. This makes it a much simpler, more straightforward approach to handling global state management in React applications.

Should we use Redux with React Hooks?

We recommend using the React-Redux hooks API as the default approach in your React components. The existing connect API still works and will continue to be supported, but the hooks API is simpler and works better with TypeScript. These hooks were first added in v7.1.0.

How do you reuse Hooks in React?

Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That's what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls.

Should you still use Redux?

The short answer is no, Redux is not necessary for React applications. However, there are always clear warning signs when you should be using a state management library like Redux and signs that you shouldn't.

Can I use Redux with hooks in react function components?

React Redux recently released version 7.1, which includes long awaited support for React Hooks. This means that you can now ditch the connect higher-order component and use Redux with Hooks in your function components. This post will take a look at how to get started using Redux with Hooks and then explore some gotchas of this approach.

What is the difference between React React and React Redux?

React also lets us write custom hooks, which let us extract reusable hooks to add our own behavior on top of React's built-in hooks. React Redux includes its own custom hook APIs, which allow your React components to subscribe to the Redux store and dispatch actions.

Should react hooks be used for architecture?

There are some architectural trade offs to take into consideration when deciding whether to use hooks or not. Mark Erikson summarizes these nicely in his two blog posts Thoughts on React Hooks, Redux, and Separation of Concerns and Hooks, HOCs, and Tradeoffs.

What is useselector in React React Redux?

React Redux now includes its own useSelector and useDispatch Hooks that can be used instead of connect. useSelector is analogous to connect ’s mapStateToProps.


2 Answers

I addressed this question in my post Thoughts on React Hooks, Redux, and Separation of Concerns and my ReactBoston 2019 talk on "Hooks, HOCs, and Tradeoffs".

I'd encourage you to read/watch through both of them, but as a summary:

  • React hooks in general lead you to a different set of organizational patterns than HOCs do, where components are more responsible for handling their own data fetching requirements internally
  • This does result in a different set of tradeoffs than HOCs offer, in terms of reusability and testability
like image 135
markerikson Avatar answered Nov 15 '22 08:11

markerikson


Hoc version (version 1) of your Count component is also "hard-wired" with particular state and dispatch. You are doing it when export default connect(mapStateToProps, mapDispatchToProps)(Count);

To compare both hoc and hook approaches to achieve Count reuse lets take a look at your original Count:

function Count(props) {
  return (
    <div>
      <button onClick={props.increment}> + </button>
      {props.count}
      <button onClick={props.decrement}> - </button>
    </div>
  );
}

And to reuse it with hocs you'll go like:

const withCount = (field, Component) => connect(
  state => ({ count: state[field] }), 
  dispatch => ({
    increment: () => dispatch({ type: 'INCREMENT', payload: field }),
    decrement: () => dispatch({ type: 'DECREMENT', payload: field })
  })
)(Component)

const NoodleCount = withCount("noodle", Count)
const DrinksCount = withCount("drinks", Count)

And for the hooks you could:

function useCount(field) {
  const count = useSelector(state => state[field]);
  const dispatch = useDispatch();
  const increment = () => dispatch({ type: 'INCREMENT', payload: field });
  const decrement = () => dispatch({ type: 'DECREMENT', payload: field });

  return {count, increment, decrement}
}

const NoodleCount = () => <Count {...useCount("noodle")} />;
const DrinksCount = () => <Count {...useCount("drinks")} />;

Obviously, there are pros and cons for both of approaches but:

Does using React Hooks drastically reduce how code can be reused in React / Redux?

No, hooks can not be the source of troubles in component reusability.

Hope it makes sense

like image 34
streletss Avatar answered Nov 15 '22 08:11

streletss