Что такое консервация штата?
Предположим следующий сценарий:
В мобильном терминале пользователь посещает страницу со списком, и в процессе прокрутки вверх и просмотра страницы со спискомвысота прокруткиПостепенно увеличивайте, данные также будут использовать днопостраничная загрузкаФорма постепенно увеличивается, просмотр страницы списка в месте, пользователь видит интерес элемент, нажмите, чтобы просмотреть детали, введите страницу сведений,При возврате на страницу списка со страницы сведений вам необходимо оставаться в позиции просмотра при выходе со страницы списка.
Подобные данные или сценарии такжеФормы заполнены, но не отправлены,Переключаемые и закрываемые метки функций в системе управленияи т. д., этот тип данных постепенно изменяется или увеличивается при взаимодействии с пользователем, под которым здесь понимаетсяусловиеВо время процесса взаимодействия, потому что некоторые причины должны быть временно оставлены, чтобы взаимодействовать друг с другом.нужно сохранить государство
существуетReact
, мы обычно используеммаршрутизацияДля управления разными страницами и при переключении страниц маршрутизация будет выгружать несопоставленные компоненты страницы, поэтому в приведенном выше примере страницы спискаКогда пользователь возвращается на страницу списка со страницы сведений, он возвращается в начало страницы списка, поскольку компонент страницы списка перестраивается после удаления маршрутом, и состояние теряется.
Как реализовать сохранение состояния в React
существуетVue
, мы можем легко пройти<keep-alive>
Тег реализует сохранение состояния, которое кэширует экземпляры неактивных компонентов, а не уничтожает их.
пока вReact
В нем нет такой функции, кто-то упомянул об этом в официальномissues, но чиновник считает, что эта функция может вызвать утечку памяти, указывая на то, что поддержка пока не рассматривается, поэтому нам нужно найти способ самостоятельно
Распространенное решение: сохранить состояние вручную
Сохранить состояние вручную, является относительно распространенным решением, которое можно комбинировать сReact
компонентcomponentWillUnmount
жизненный цикл черезredux
Уровень управления состоянием, такой как уровень управления состоянием, сохраняет данные посредствомcomponentDidMount
Периодическое восстановление данных
Когда есть несколько состояний, которые нужно сохранить, этот метод может относительно быстро достичь нужных нам функций, но когда объем данных велик или ситуация изменчива, ручное сохранение состояния станет хлопотным делом.
Как программист вы, конечно, максимально ленивы, чтобы каждый раз не заботиться о том, как сохранять и восстанавливать данные, надо учитьсяКак сохранить состояние автоматически
Автоматическое сохранение состояния через маршрутизацию (обычно с использованиемreact-router)
Поскольку потеря состояния в React вызвана выгрузкой компонентов при переключении маршрута, можно попробовать начать с механизма маршрутизации.Измените поведение рендеринга маршрута к компоненту
У нас есть следующие способы достижения этой функции
-
переписать
<Route>
компоненты, вы можете обратиться кreact-live-routeПереписывание может обеспечить желаемую функцию, но стоимость относительно высока, нам нужно обратить внимание на оригинал
<Route>
сохранение функции и многократноеreact-router
совместимость версий -
Переписать библиотеку маршрутизации, вы можете обратиться кreact-keeper
Стоимость переписывания библиотеки маршрутизации неподъемна для обычных разработчиков, а полностью заменять схему маршрутизации рискованно, что требует тщательного рассмотрения.
-
на основе
<Route>
Расширить существующее поведение компонента, вы можете обратиться кreact-router-cache-routeво время чтения
<Route>
После исходного кода найдите, что если используетсяcomponent
илиrender
атрибут, не может избежать участи удаления маршрута, если он не соответствуетно будет
children
Атрибуты используются как методы, у нас есть возможность вручную управлять поведением рендеринга, код ключа здесьGitHub.com/реагировать поезд я…// 节选自 Route 组件中的 render 函数 if (typeof children === "function") { children = children(props); // children 是函数时,将对 children 进行调用得到真实的渲染结果 if (children === undefined) { ... children = null; } } return ( <RouterContext.Provider value={props}> {children && !isEmptyChildren(children) ? children // children 存在时,将使用 children 进行渲染 : props.match ? component ? React.createElement(component, props) : render ? render(props) : null // 使用 render 属性无法阻止组件的卸载 : null // 使用 component 属性无法阻止组件的卸载 } </RouterContext.Provider> );
Основываясь на приведенном выше исследовании исходного кода, мы можем
<Route>
Развернуть, будет<Route>
несоответствие поведенияИзменено с удаления на скрытый,следующим образом<Route exact path="/list"> {props => ( <div style={props.match ? null : { display: 'none' }}> <List {...props} /> </div> )} </Route>
Выше описан самый простой способ настройки, в реальных ситуациях также необходимо учитывать скрытое состояние.
match
дляnull
Проблема, из-за которой компонент сообщает об ошибке, и поскольку компонент больше не удаляется, иTransitionGroup
Координация не очень хорошая, что затрудняет анимацию перехода.использоватьreact-router-cache-route, полученный эффект примерно такой, как показано ниже,
Вышеизложенное исследует возможность автоматического сохранения состояния через маршрутизацию, а также существующие реализации, но в конце концов это не реально и не чисто.KeepAlive
функция, то мы пытаемся исследовать реальнуюKeepAlive
Реализация функции
имитировать реальный<KeepAlive>
Функция
Вот ожидаемое использование
function App() {
const [show, setShow] = useState(true)
return (
<div>
<button onClick={() => setShow(show => !show)}>Toggle</button>
{show && (
<KeepAlive>
<Test />
</KeepAlive>
)}
</div>
)
}
Принцип реализации относительно прост, посколькуReact
выгружает компоненты во встроенной иерархии компонентов, поэтому нам нужно<KeepAlive>
компоненты вchildren
Атрибуты извлекаются и отображаются в компоненте, который не будет удален.<Keeper>
внутри, использовать сноваDOM
операция будет<Keeper>
Настоящий контент внутри перемещается в соответствие<KeepAlive>
, вы можете выполнить эту функцию
Вот самый простой, меньше 70 строк<KeepAlive>
Пример реализации:минимальная реализация
Ниже приведеныreact-activationэффект реализации
На картинке ниже<KeepAlive>
Принцип реализации
В процессе фактической реализации возникло много проблем, все из-за нарушения исходного кода.React
обусловлены иерархическими отношениями, такими как
- задержка рендеринга (
react-activation
было исправлено) -
Context
Функция контекста не работает (react-activation
было исправлено) -
Error Boundaries
неверный (react-activation
было исправлено) -
React.Suspense
&React.lazy
неверный (react-activation
было исправлено) - Сбой всплытия синтетических событий React
- Другие неизвестные функции
Тем не менее, большинство из вышеперечисленных проблем можно устранить с помощью механизма моста.Подробности см. здесь.issues
Такая же, более ранняя реализация также имеетreact-keep-alive
Эпилог
Кэширование состояния является очень распространенным требованием в приложениях.Когда объем обрабатываемых данных невелик, большинство проблем можно решить с помощью ручного кэширования состояния.Однако, когда ситуация сложная, необходимо попытаться решить функцию кэширования отдельно, так что Лучшее разделение интересов во время развития бизнеса
Текущая реализация имеет свои проблемы, но процесс ее изучения очень интересен. Лучший способ по-прежнему - это официальная поддержка, но я не могу ожидать слишком многого в данный момент.