Уменьшает ли использование React Hooks то, как можно повторно использовать код в React / Redux? - PullRequest
6 голосов
/ 21 апреля 2020

Допустим, у нас есть старый традиционный способ React / Redux: (вам не нужно расширять код, если вы знакомы с ним:)

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);

Теперь, используя React Hooks useSelector() и useDispatch(), приведенный выше код можно записать так:

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;

Обе версии работают одинаково сами по себе, за исключением того, что версия 1 не может использоваться повторно для Count? Это потому, что используя разные mapStateToProps() и mapDispatchToProps(), мы можем снова использовать connect() для создания другого CountNoodle(), и теперь мы повторно использовали Count().

Для версии 2 Count() сложно - с каким состоянием и диспетчеризацией он использует, поэтому весь Count() не подлежит повторному использованию. То есть, должен использоваться с этим конкретным состоянием и конкретной отправкой, но больше ничего. Разве это не правда? Так что версия 2 выше не рекомендуется, и на самом деле у вас будет версия 3, которая не будет называть ее Count(), а будет называть ее CountNoodle() и "связывать" состояние и отправлять, и повторно использовать Count(), что будет просто "презентационным"?

Так что это может выглядеть примерно так:

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;

Ответы [ 2 ]

1 голос
/ 21 апреля 2020

Ho c версия (версия 1) вашего Count компонента также «аппаратно» связана с определенным состоянием и отправкой. Вы делаете это, когда export default connect(mapStateToProps, mapDispatchToProps)(Count);

Чтобы сравнить подходы ho c и hook для достижения Count повторного использования, давайте взглянем на ваш оригинальный Count:

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

И для повторного использования с hocs вы будете go вроде:

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)

И для хуков вы можете:

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")} />;

Очевидно, что для обоих подходов есть свои плюсы и минусы но:

Значительно ли уменьшает использование React Hooks возможности повторного использования кода в React / Redux?

Нет, перехватчики не могут быть источником проблем при повторном использовании компонента.

Надеюсь, это имеет смысл

0 голосов
/ 21 апреля 2020

Я отвечал на этот вопрос в своем посте Мысли о React-хуках, Redux и разделении проблем и мой ReactBoston 2019-й доклад о "Крюках, HOC и компромиссах" .

Я бы посоветовал вам прочитать / посмотреть оба из них, но вкратце:

  • В целом, реагирующие хуки приводят вас к другому набору организационных паттернов, чем HOC, где компоненты в большей степени отвечают за внутреннюю обработку своих собственных требований по извлечению данных
  • Это приводит к другому набору компромиссов, чем предлагают HOC, с точки зрения возможности повторного использования и тестируемости
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...