Объяснение и примеры новых хуков в React (3)

JavaScript React.js

Ставь лайк и смотри, поиск в WeChat【Переезд в мир】Обратите внимание на этого человека, который не имеет большого фабричного прошлого, но имеет восходящий и позитивный настрой. эта статьяGitHub GitHub.com/QQ449245884…Он был включен, статьи были классифицированы, и многие мои документы и учебные материалы были систематизированы.

Все говорили, что нет проекта для написания резюме, поэтому я помог вам найти проект, и это было с бонусом.【Учебник по строительству】.

Эта статья является третьей в серии React

Объяснение и примеры новых возможностей React (1)

Объяснение и примеры новых хуков в React (2)

Чтобы прочитать больше качественных статей, нажмитеБлог GitHub, Сотни качественных статей ждут вас каждый год!

Использование контекстных хуков

Использование Context , впервые объявленного на верхнем уровнеProvierкомпоненты и объявитьvalueсвойства, затем объявленные в компонентах-потомкахConsumerкомпонент, этоConsumerПодкомпонент, может быть только уникальной функцией, параметр функцииContextнагрузка. Если есть несколькоContext ,Providerа такжеConsumerВложенные в любом порядке.

Кроме того, мы также можем настроить таргетинг на любойContextиспользоватьcontextTypeупростить этоContextполучение нагрузки. Но в компоненте, даже потребляющем несколькоContext,contextTypeможет указывать только на один из них

В среде Hooks вы все еще можете использоватьConsumer,ноContextTypeСтатический член класса определенно бесполезен. Крючки обеспечиваютuseContext, который не только решает проблему, которую Consumer сложен в использовании, но и решаетcontextTypeиспользовать только одинcontextЭта проблема.

Вот пример использования формы класса:

class Foo extends Component {
  render() {
    return (
      <CountContext.Consumer>
        {
          count => <h1>{count}</h1>
        }
      </CountContext.Consumer>
    )
  }
}

function App (props) {
  const [count, setCount] = useState(0);

  return (
    <div>
      <button type="button"
        onClick={() => {setCount(count + 1) }}
      >
        Click({count})
      </button>
      <CountContext.Provider value={count}>
        <Counter />
      </CountContext.Provider>
    </div>
  )
}

Объяснять вышесказанное не буду, первая часть уже сказана, а дальше будуFooизменить на использованиеcontextTypeформа:

class Foo extends Component {
  static contextType = CountContext;
  render() {
    const count = this.context
    return (
      <h1>{count}</h1>
    )
  }
}

затем используйтеuseContextформа:

function Foo () {
  const count = useContext(CountContext)
  return (
    <h1>{count}</h1>
  )
}

useContextполучитьcontextобъект (возвращаемое значение React.createContext ) и возвращает текущее значение этого контекста. Текущее значение контекста определяется ближайшим компонентом верхнего компонента к текущему компоненту.<CountContext.Provider>Ценностная опора определена.

Когда самый последний над компонентом обновляется, этот хук вызовет повторную визуализацию с последним значением контекста, переданным поставщику CountContext.

Не забудьuseContextАргумент должен бытьcontextСам объект:

  • Правильно: использоватьContext(MyContext)
  • Ошибка: useContext(MyContext.Consumer)
  • Ошибка: useContext(MyContext.Provider)

называетсяuseContextкомпоненты всегда будут вcontextПовторно рендерится при изменении значения. Если повторный рендеринг компонента обходится дорого, вы можете оптимизировать его с помощью мемоизации.

Использование мемо-хуков

Meno используется для оптимизации поведения повторного рендеринга функциональных компонентов.Когда входящие значения свойств не изменяются, повторный рендеринг компонента не будет запускаться, в противном случае он вызовет повторный рендеринг компонента.

useMemo и памятка

menoПовторяется ли рендеринг компонента, иuseMemoОпределено, повторяется ли логика функции.

Вот кукуруза:

function Foo (props) {
  return (
    <h1>{props.count}</h1>
  )
}
function App (props) {
  const [count, setCount] = useState(0);

  const double = useMemo(() => {
    return count * 2
  }, [count])
  
  return (
    <div>
      <button type="button"
        onClick={() => {setCount(count + 1) }}
      >
        Click({count}) double: ({double})
      </button>
      <Foo count={count}/>
    </div>
  )
}

результат операции:

Как показано выше,useMemoграмматика иuseEffectсогласуется. Первый параметр — это логическая функция, которую необходимо выполнить, а второй параметр — это массив входных переменных, зависящих от логики, если второй параметр не передан, этоuseMemoЛогика будет работать каждый раз,useMemoСмысла самого по себе не существует, поэтому необходимо передать параметры. Таким образом, передача пустого массива будет выполняться только один раз, и стратегия такая же, какuseEffectто же самое, но есть большая разница в времени вызова,useEffectИсполнение является побочным эффектом, поэтому его нужно выполнять после рендеринга, ноuseMemoТребуется возвращаемое значение, и возвращаемое значение может напрямую участвовать в рендеринге, поэтомуuseMemoвыполняется во время рендеринга.

Далее переделыватьuseMemo, сделать его зависящим отcountследующим образом:

const double = useMemo(() => {
  return count * 2
}, [count])

Только потом считать изменения,useMemoбудет казнен.

Снова измените useMemo следующим образом:

const double = useMemo(() => {
  return count * 2
}, [count === 3])

Теперь можно сделать вывод, чтоcountПока он не будет равен 3, он сохраняется из-за этого условияfalseбез изменений, двойное число не будет пересчитываться, поэтому оно всегда равно 0, когдаcountравно 3,doubleпересчитывается на 6, когдаcountбольше 3,doubleПосле пересчета становится 8, а потом сохраняет 8 без изменений.

Помните, входящиеuseMemoФункция будет выполняться во время рендеринга, пожалуйста, не выполняйте внутри этой функции ничего, не связанного с рендерингом, такие операции, как побочные эффекты, относятся кuseEffectсферы применения, а неuseMemo.

Вы можете использовать useMemo для оптимизации производительности, но не в качестве семантической гарантии.

Использование хуков useCallback

Далее рассмотрим использованиеmemoПример оптимизации подкомпонентов.

const Foo = memo (function Foo (props) {
  console.log('Counter render')
  return (
    <h1>{props.count}</h1>
  )
})

function App (props) {
  const [count, setCount] = useState(0);

  const double = useMemo(() => {
    return count * 2
  }, [count === 3])

  return (
    <div style={{padding:'100px'}}>
      <button type="button"
        onClick={() => {setCount(count + 1) }}
      >
        Click({count}) double: ({double})
      </button>
      <Foo count={double}/>
    </div>
  )
}

использоватьmemoпакетFooкомпонентов, так что только когдаdoubleИзменения,FooКомпонент будет перерендерен, и журнал внутри будет выполнен, результаты следующие:

сейчас даюFooсерединаh1добавить одинclickмероприятие:

const Foo = memo (function Foo (props) {
  console.log('Counter render')
  return (
    <h1 onClick={props.onClick}>{props.count}</h1>
  )
})

Затем объявите onClick в компоненте приложения и передайте егоFooКомпоненты:

function App (props) {
  ...
  const onClick = () => {
    console.log('Click')
  }

  return (
    <div style={{padding:'100px'}}>
      ...
      <Foo count={double} onClick={onClick}/>
    </div>
  )
}

Взгляните на эффект операции:

Видно, что каждый щелчок, независимо отdoubleесть ли какие-то изменения,FooКомпоненты визуализируются. Это означает, что каждый раз, когда приложение перерисовывается,onClickОбработка изменений, в результате чегоFooОн также был перерисован.countМенять часто можно, ноonClickВ конце концов, он не должен часто меняться, это всего лишь функция, поэтому мы должны найти способ сделать так, чтобыonClickРучка не меняется.

Подумайте о том, что мы сказали вышеuseMemo, который можно оптимизировать следующим образомonClick:

const onClick = useMemo(() => {
  return () => {
    console.log('Click')
  }
}, [])

Поскольку мы проходимuseMemoВторой параметр — это пустой массив, тогда вся логика запустится только один раз, теоретически мы вернемсяonClickЕсть только одна ручка.

текущий результат:

Теперь мы ставимuseCallbackчтобы перейти на предыдущую страницуuseMemoлогика.

const onClick = useCallback(() => {
  console.log('Click')
},[])

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

useCallback(fn, deps) 相当于 useMemo(() => fn, deps)

У вас может возникнуть вопрос,useCallbackЭти строки кода явно создают новую функцию при каждом рендеринге компонента, так как это оптимизирует производительность.

Обратите внимание, не поймите меня неправильно, используйтеuseCallbackЭто правда, что создание новой функции невозможно предотвратить, но эта функция не обязательно возвращается, а это означает, что вновь созданная функция может быть отброшена.useCallbackРешение состоит в том, чтобы решить проблему, заключающуюся в том, что параметры функции, переданные в подкомпонент, изменяются слишком сильно, что приводит к чрезмерному рендерингу подкомпонента, что здесь необходимо хорошо понимать.

Пустой массив, переданный нашим вторым параметром выше, не так прост в реальном бизнесе, по крайней мере, нам нужно обновить статус. Возьмите просо:

function App (props) {
  ... 
  const [clickCount, setClickCount] = useState(0);
  const onClick = useCallback(() => {
    console.log('Click')
    setClickCount(clickCount + 1)
  },[clickCount, setClickCount])
  ...
}

В компоненте APP объявитеuseState, затем вonClickвызыватьsetClickCount, на этот раз onClick зависит отclickCount,setClickCount.

На самом деле здесьsetClickCountНе нужно писать, потому что React может гарантироватьsetStateОдин и тот же дескриптор возвращается каждый раз. Если вы мне не верите, вы можете посмотреть официальную документацию:

Вот сцена, в дополнение к прямому использованиюsetClickCount + 1Помимо присваивания, есть еще один способ дажеclickCountНе полагайтесь на это.setStateПомимо прохождения в соответствующемstateВ дополнение к последнему значению также может быть передана функция, и параметр функции такойstateТекущее значение , возвращаемое значение — это значение для обновления:

const onClick = useCallback(() => {
  console.log('Click')
  setClickCount((clickCount) => clickCount + 1)
},[])

резюме

а такжеmemoТо же, что и при принятии решения о повторной визуализации компонента на основе свойства.useMemoМожно оптимизировать производительность, не решая, следует ли повторно выполнять часть логики функции на основе указанных зависимостей.

еслиuseMemoЕсли возвращаемое значение является функцией, то его можно сократить какuseCallbackЭтот метод является просто сокращением, и на самом деле нет никакой разницы.

Важно отметить, что при изменении зависимостей мы можем сделать вывод, чтоuseMemoБыть повторно казненным. Однако, даже если он не изменится, мы не можем предположить, что он не будет повторно выполняться, то есть он может выполняться, это считать результаты оптимизации.

мы можем поставитьuseMemo, useCallbackВишенкой на торте является то, что вы не можете слишком полагаться на то, будет ли он перерендерен, потому что React в настоящее время не имеет гарантии, что он должен выполняться или не выполняться.

общаться с

Статья постоянно обновляется каждую неделю. Вы можете выполнить поиск «Big Move to the World» в WeChat, чтобы прочитать и обновить ее как можно скорее (на одну или две статьи раньше, чем в блоге). Эта статья находится на GitHub.GitHub.com/QQ449245884…Он был включен, и многие мои документы были разобраны. Добро пожаловать в Звезду и совершенство. Вы можете обратиться в тестовый центр для ознакомления во время собеседования. Кроме того, обратите внимание на паблик-аккаунт и ответьте в фоновом режиме.Благосостояние, вы можете увидеть преимущества, вы знаете.