Строгое равенство (===) в сравнении с проверками на неглубокое равенство в React-Redux - PullRequest
4 голосов
/ 03 октября 2019

Я изучаю, как работают API-интерфейсы Hooks, предоставляемые React-Redux-v.7.1 , и увидел, что это упоминалось в Сравнения и обновления равенства (https://react -redux.js.org/api/hooks#equality-comparisons-and-updates) что:

" Начиная с v7.1.0-alpha.5 сравнение по умолчанию является строгим === Сравнение ссылок. Это отличается от connect () , который использует поверхностные проверки на равенство по результатам вызовов mapState , чтобы определить, требуется ли повторный рендерингЭто имеет несколько последствий для использования useSelector () ."

Мне интересно почему строгое равенство лучше, чем поверхностное равенство, которое используется Connect () ? Затем я изучил их сравнения на равенство:

Стандартная строгая проверка на равенство useSelector () просто проверяет a === b

const refEquality = (a, b) => a === b

И проверки на равенство в response-redux / src / connect / connect.js использует Object.is () , а также другие проверки, которыетак же, как в реагирует .

// The polyfill of Object.is()
function is(x, y) {
  if (x === y) {
    return x !== 0 || y !== 0 || 1 / x === 1 / y
  } else {
    return x !== x && y !== y
  }
}

export default function shallowEqual(objA, objB) {
  if (is(objA, objB)) return true

  if (
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null
  ) {
    return false
  }

  const keysA = Object.keys(objA)
  const keysB = Object.keys(objB)

  if (keysA.length !== keysB.length) return false

  for (let i = 0; i < keysA.length; i++) {
    if (!hasOwn.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
      return false
    }
  }

  return true
}

Согласно описанию Object.is () в MDN:" Object.is не выполняет преобразование типов и не обрабатывает специальные значения для NaN, -0 и +0 (придает такое же поведение, что и ===, за исключением тех специальных числовых значений )."

Понятия не имею, почему a === b лучше, чем серия проверок на равенство. (Я впервые задаю вопросы здесь, извиняюсь за грубость или недостаток информации)

1 Ответ

2 голосов
/ 03 октября 2019

С connect, mapStateToProps возвращает составной объект со всеми состояниями, выбранными из хранилища, поэтому имеет смысл поверхностное сравнение по его ключам. При useSelector шаблон часто должен возвращать только одно значение для каждого вызова useSelector, аналогично тому, как хук useState обрабатывает только одно значение вместо всех значений состояния. Таким образом, если каждый вызов useSelector возвращает значение напрямую, тогда строгая проверка на равенство имеет смысл против поверхностного сравнения. Короткий пример должен прояснить это.

import {connect} from 'react-redux';

const mapStateToProps = state => (
  {keyA: state.reducerA.keyA, keyB: state.reducerB.keyB}
);
export default connect(mapStateToProps)(MyComponent);

Здесь mapStateToProps вызывается каждый раз, когда хранилище изменяется каким-либо образом, поэтому возвращаемое значение всегда будет новым объектом, даже если keyA иkeyB не меняется. Таким образом, поверхностное сравнение используется для определения необходимости повторного рендеринга.

Для случая ловушек:

import {useSelector} from 'react-redux';

function MyComponent(props) {
  const keyA = useSelector(state => state.reducerA.keyA);
  const keyB = useSelector(sate => state.reducerB.keyB);
  ...
}

Теперь результатом ловушек useSelector являются отдельные значения измагазин, а не составной объект. Так что использование строгого равенства в качестве значения по умолчанию здесь имеет смысл.

Если вы хотите использовать только один хук useSelector, который возвращает составной объект, у документов, на которые вы ссылаетесь, есть пример использования shallowEqual равенствафункция: https://react -redux.js.org / api / hooks # равенство сравнений и обновлений

...