Введение
В процессе фронтенд-разработки есть риск, о котором разработчики должны быть бдительны, то есть в нормальных условиях проблемы нет, но из-за небольшого онлайна или развёртывания сервера возникают онлайн баги, а тем более онлайн-баги и онлайн-баги Содержание не имеет значения, поэтому сегодня я поделюсь с вами реальным случаем.
Знания, охватываемые в этом случае, следующие:
- 1 Спецификации для установки зависимых пакетов в проект.
- 2 Подписка потребления контекста.
- 3
react-router
V5.2.0 версия меняется. - 4 местных и онлайн-расследования несчастных случаев.
Два проблемных фона
Далее я расскажу о конкретных проблемах.Недавно одноклассник (псевдоним Сяомин) столкнулся с проблемой в разработке, то есть с онлайн-аварией, вызванной использованием React-Router. Источником аварии является то, что он используется в глобальном компонентеReact-Router
Кастомные хуки в - useHistory, подробности таковы.
import { useHistory } from 'react-router'
function Index(){
/* 获取 histroy 对象 */
const history = useHistory()
console.log(history)
return <div>
{/* 展示 history 里面信息,期望当 history 中 location 信息变化的时候,组件也能更新 */}
</div>
}
Для СяоминReact-Router
серединаuseHistory
чтобы получить состояние в объекте истории. и ожидать:
- Отображение полей в местоположении.
- При переходе маршрута и изменении истории ожидается, что индекс компонента также будет повторно визуализирован для обновления отображаемого содержимого.
Эта функция работает без проблем в проекте. Но недавно Сяо Мин разработал новую функцию, не имеющую ничего общего с текущим компонентом, и выложил ее в сеть.
В результате в сети произошла авария:При изменении маршрутаIndex
Компоненты больше не обновляются, как раньше.
Что еще более невероятно, так это то, что у Сяомина не будет проблем в местной среде. Так что эта проблема также появилась в Интернете. То есть эта проблема возникает только в Интернете.
Этот внезапный вопрос заставил Сяо Мина смутиться и запаниковать. Так что же вызывает это?
Три решения проблемы
Локальный и онлайн разные
Далее давайте поможем Сяомину решить эту проблему. Итак, сначала 🤔 подумайте об этом:Почему возникает несоответствие между локальным и онлайн?
Несоответствие между онлайн и локальным, то в этом случае первое, о чем следует подумать,Это линейно-зависимый пакет и локальная разница?. Затем проверка также очень проста, то есть нужно обновить все локальные пакеты, потому что пакеты, развернутые онлайн, обычноinstall
новый пакет. Затем вы можете проверить это следующим образом:
- скачать локальный
node_modules
; - переустановить
npm install
Попробовав вышеупомянутые решения, я обнаружил, что локальный феномен такой же, как и онлайн. Тогда возникает новая проблема: Сяомин вообще никогда не обновлял зависимости проекта, так почему же существует разница в пакетах зависимостей?
По сути это связано с механизмом установки пакетов npm, то есть, например, если ваш проект зависит от x.x.x версии модуля a, то после того, как деплой выйдет в онлайн, в проекте должна быть установлена x.x.x версия a? Ответ — нет, как работать с npm, будет рассказано позже. В приведенной выше ситуации сначала анализируется, что проблема возникает вReact-Router
Библиотека, так что смотрите проект Xiao Mingpackage.json
"react-router": "^5.1.2",
- Как вы можете видеть выше, проект Сяомин использовал
react-router
да5.1.2
версия, то проблема с ^ .
механизм установки версии npm
^ вpackage.json
что это значит вpackage.json
середина^Будет соответствовать последней основной версии пакета зависимостей. Например:
- Если версия зависимости написана так
^1.2.3
, что означает установить последнюю версию 1.х.х (не ниже 1.2.3, включая 1.3.0), но не ставить 2.х.х, то есть при установке основной номер версии не меняется.
Тогда Сяомин в проекте^5.1.2
написано так, то если есть более поздняя версияreact-router
Например5.2.x
,5.3.x
, то последний установочный пакет будет загружен до6.0.0
пока (6.0.0 устанавливаться не будет).
Следует отметить, что если основной номер версии равен 0, знак вставки ведет себя так же, как и тильда, потому что в настоящее время он находится в стадии разработки, и даже если дополнительный номер версии изменится, он может привести к несовместимости программы. (основная версия)
Например^0.2.3
Тогда диапазон версий, представляющий установку, равен>=0.2.3 <0.3.0
.
Соответствие версии зависимостей
символ | пример | Объем | иллюстрировать |
---|---|---|---|
^ будет соответствовать последней основной версии пакета зависимостей | ^1.2.3 | >=1.2.3 | Указывает, что установлена последняя версия 1.х.х (не ниже 1.2.3, включая 1.3.0), но не установлена 2.х.х, то есть номер основной версии при установке не меняется. |
~ Будет соответствовать самой близкой маленькой версии зависимого пакета | ~1.2.3 | >=1.2.3 <1.3.0 | Представляют последнюю версию 1.2.x (не менее 1.2.3), но не устанавливается 1.3.x, не изменяет основной номер версии и устанавливается второстепенный номер версии. |
>= | >=2.1.0 | >=2.1.0 | Больше или равно 2.1.0 |
<= | <=2.0.0 | <=2.0.0 | Меньше или равно 2.0.0 |
laster | -- | -- | Установите последнюю версию |
* | -- | -- | любая версия |
- | 1.2.3 - 2.3.4 | >=1.2.3 <=2.3.4 | между двумя версиями |
Итак, давайте вернемся к проблеме, с которой столкнулся Сяомин.Теперь, когда мы знаем, что причина в автоматическом обновлении, что, если мы решим эту проблему?
Настало время решить проблему,Если есть ошибки, вызванные различиями между онлайн- и локальной версиями, самый прямой и быстрый способ — исправить версию.
"react-router": "5.1.2",
Символ перед номером версии не добавляется, версия фиксирована5.1.2
, наиболее фундаментальное и эффективное решение проблемы.
Очевидно это не лучший ответ, в первую очередь следует начать с сути проблемы, почемуreact-router
Больше невозможно подписаться на информацию о маршрутизации через историю использования. Так что же на самом деле изменилось? мы нашлиreact-routerV5.1.2
исходный код,
export function useHistory() {
return useContext(Context).history;
}
- Как видно выше
useHistory
По сути, вызовuseContext
, который использует всю библиотеку маршрутизацииContext
изhistory
объект. - Вся информация о состоянии маршрутизации хранится в Context.Каждый раз, когда маршрутизация изменяется, компонент маршрутизации уведомляется об отображении соответствующего представления посредством изменения Context. Для студентов, не знакомых с React Router, можно прочитать еще одну статью автора:"Анализ исходного кода" На этот раз я полностью понимаю принцип маршрутизации react-router
Если вы не знакомы с механизмом потребления контекста подписки, пожалуйста, прочитайте ниже.
механизм потребления контекста
useHistory по существу использует useContext, который по существу подписывается на новую версию объекта React Context. Здесь необходимо ввести механизм обновления подписки React Context.
Новая версия объекта Context включает провайдеровProvider
и подписчикиConsumer
:
-
Provider
: передать значение значения контекста. -
Consumer
: использовать значение, предоставленное поставщиком. - компонент класса
contextType
и функциональные компонентыuseContext
Вы также можете подписаться на потребление значения контекста, и когда значение контекста изменится, они будут повторно отображены и не будут затронутыPureComponent
,memo
,shouldComponentUpdate
Влияние стратегий оптимизации.
Вернемся к проблеме, с которой столкнулся Сяомин: до того, как Сяомин использовал useHistory для подписки на изменения маршрутизации, когдаОбновление маршрута, затем компоненты, использующие useHistory, будут повторно отображаться, потому что предыдущая логика заключается в том, что обновления маршрутизации будут обновлятьсяhistory
объект . Смоделируем процесс.
const Context = React.createContext()
function useName (){
return React.useContext(Context).name
}
const Child = ()=>{
const name = useName()
return <div>
{name}
</div>
}
const Index = memo(function(){
return <div>
<p>root 组件 </p>
<Child/>
</div>
})
export default function App(){
const [ value , changeValue ] = React.useState({ name:'列表' , path:'/list' })
return <div>
<Context.Provider value={value} >
<Index />
</Context.Provider>
<button onClick={()=> changeValue({ name:'首页',path:'/detail' })} >改变 value </button>
</div>
}
Эффект:
- Переключение маршрутов эквивалентно вызову
changeValue
,измененныйProvider
серединаvalue
. - Компонент, используемый Xiao Ming, — это Child , а
useHistory
похожий наuseName
. - Изменение значения при нажатии кнопки. Ребенок обновляет представление.
Ревизия реактивного маршрутизатора
Механизм обновления контекста подписки известен выше, так почему же текущийuseHistory
Тогда новая версияreact-router
Что изменилось? Позже я проверил журнал обновлений и обнаружил, что вreact-router
В v5.2.0 был извлечен Контекст истории, и у него уже есть свой Контекст.
ЭтоReleases
Записывать:
Затем мы снова посмотрели на исходный код:
export function useHistory() {
return useContext(HistoryContext);
}
export function useLocation() {
return useContext(Context).location;
}
Из вышеизложенного вы можете увидеть:
- useHistory больше не подписан
Context
, ноHistoryContext
. - useLocation все еще подписывайтесь
Context
. - Когда мы меняем маршрут, существенно меняется
Context
, поэтому используйтеuseLocation
Компоненты будут обновляться с использованиемuseHistory
компоненты не будут обновляться.
В этот момент я вдруг понял, что правда наконец всплыла наружу.
Четыре резюме
Изучив данную статью, вы сможете получить следующее содержание:
- Устранение сетевых и локальных несоответствий.
-
package.json
Проблема с номером версии. - Принцип использования История.
- Контекст подписывается на процесс обновления.
Я надеюсь, что студенты, которые чувствуют, что они что-то добились, могут лайкнуть + подписаться на автора и продолжать делиться хорошими фронтенд-статьями.