React Hooks - Как мне реализовать shouldComponentUpdate? - PullRequest
0 голосов
/ 06 февраля 2019

Я знаю, что вы можете указать React пропустить эффект, передав массив в качестве необязательного второго аргумента.

Например:

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes

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

Я ожидал бы что-то вроде React.memo, что вы можете передать функцию в качестве второго аргумента.

Ответы [ 3 ]

0 голосов
/ 07 мая 2019

Вот пользовательский хук, который принимает функцию средства обновления и возвращает значение, которое изменяется только тогда, когда функция средства обновления возвращает значение true, которое может быть передано во втором аргументе в useEffect или useCallback или useMemo, чтобы принудительно вызватьповторное рендеринг:

function useShouldRecalculate(shouldRecalculateFn) {
  const prevValueRef = useRef(0);
  if(shouldRecalculateFn()) {
    // If we need to recalculate, change the value we return
    prevValueRef.current += 1;
  } // else we return the same value as the previous render, which won't trigger a recalculation
  return prevValueRef.current;
}

Например, это будет обновлять заголовок документа только в том случае, если число четное:

const shouldUpdateTitle = useShouldRecalculate(
  () => count % 2 === 0
);

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [shouldUpdateTitle]); // eslint-disable-line react-hooks/exhaustive-deps

Почему вы, вероятно, не должны этого делать

В большинстве случаев я бы не рекомендовал это делать.

Как правило, будут более понятные способы решения той же задачи с использованием API идиоматических перехватчиков.(В приведенном выше примере можно было бы просто поместить блок if вокруг строки, которая обновляет заголовок документа.)

Возможно, еще важнее, что аргумент deps касается не только оптимизации, но и сохранения значений закрытияактуальный и избегающий ошибок, таких как:

const [count, setCount] = useState(0)
const increment = useCallback(() => {
    // Bug: `count` is always 0 here, due to incorrect use of the `deps` argument
    setCount(count + 1)
}, [])

Эта ошибка будет обнаружена правилом react-hooks/exhaustive-deps linter, но вам придется отключить это правило везде, где вы используете собственную логику для управлениявыполнение.

Использование настраиваемой логики запоминания, вероятно, сделает ваши компоненты более подверженными ошибкам и в целом будет сложнее рассуждать.Так что я бы посчитал этот useShouldRecalculate крючок чем-то вроде последнего средства.

0 голосов
/ 08 августа 2019

В комментарии выше Gabriele Petrioli ссылается на документацию React.memo, которая объясняет, как реализовать shouldComponentUpdate.Я прибегал к поиску комбинацийинов shouldComponentUpdate + useEffect + «реагировать на крючки», и в результате это получилось.Поэтому, решив мою проблему со связанной документацией, я подумал, что я тоже приведу сюда эту информацию.

Это старый способ реализации shouldComponentUpdate:

class MyComponent extends React.Component{
  shouldComponentUpdate(nextProps, nextState){
    return nextProps.value !== this.props.value;
  }
  render(){
    return (
     <div>{"My Component " + this.props.value}</div>
    );  
 }
}

Новый способ React Hooks:

React.memo(function MyComponent (props) {

  return <div>{ "My Component " + props.value }</div>

}) 

Я знаю, что вы, вероятно, задавали больше вопросов в своем вопросе, но для всех, кто приходит из Google и смотрит, как реализовать shouldComponentUpdate, все готово.

Документация здесь: как-д-я орудие-shouldcomponentupdate

0 голосов
/ 13 марта 2019

Передача необязательного второго аргумента массива запускает функцию эффекта, если передается свойство, переданное в массиве, - точно так же, как метод shouldComponentUpdate в компоненте класса запускается, когда реквизиты передаются компоненту.В функции эффекта вы можете решить, основываясь на значении параметра - хотите ли вы применить эффект или нет.

...