Отслеживание изменений состояния с помощью плагина Zustand
Zustand — это очень быстрая и минималистичная замена решениям для управления состоянием, таким как Redux. С помощью нашего плагина Zustand вы можете отслеживать изменения состояния на протяжении всего жизненного цикла вашего приложения.
Установка плагина
Section titled Установка плагинаПлагин можно легко установить с помощью следующей команды:
npm i @openreplay/tracker-zustand
Использование плагина в приложении Next.js
Section titled Использование плагина в приложении Next.jsПримечание: полный исходный код этого примера находится в этом репозитории Github, загляните туда, если вам нужны дополнительные подробности.
Провайдер Context, который я использую, позволяет настраивать Tracker Plugins, поэтому после установки плагина мы изменим файл _app.tsx, добавив приведённую ниже инструкцию импорта:
import trackerZustand from '@openreplay/tracker-zustand'
А затем основная функция App должна выглядеть так:
export default function MyApp({ Component, pageProps }: AppProps) {
const Layout = (Component as any).Layout || Noop
useEffect(() => {
document.body.classList?.remove('loading')
}, [])
let plugins = [
{
fn: trackerZustand,
name: 'zustand',
},
]
return (
<TrackerProvider
config={{
plugins
}}
>
<Head />
<ManagedUIContext>
<Layout pageProps={pageProps}>
<Component {...pageProps} />
</Layout>
</ManagedUIContext>
</TrackerProvider>
)
}
Это автоматически инициализирует плагин вместе с трекером, а также сделает доступными данные, возвращаемые при выполнении основной функции плагина.
Следующий шаг — создать store; через минуту мы будем добавлять в этот store товары с сайта электронной коммерции.
Создание store с помощью плагина Zustand
Section titled Создание store с помощью плагина ZustandИспользование плагина требует изменить способ, которым вы обычно создаёте экземпляр store Zustand, поэтому смело копируйте и вставляйте следующий код в качестве шаблона:
import create from 'zustand'
const productStore = null
export const useProductsStore = (logger) => {
if (!productStore) {
//use a singleton pattern to make sure we only create the store the first time around
productStore = createProductStore(logger)
}
return productStore
}
function createProductStore(logger) {
return create(
logger((set) => ({
products: [],
addProduct: (p) =>
set((state) => {
const prodFound = state.products.find((prod) => {
return p.id == prod.id
})
if (prodFound) {
p.amount = prodFound.amount + 1
} else {
p.amount = 1
}
return {
products: [...state.products.filter((prod) => p.id != prod.id), p],
}
}),
}))
)
}
Экспортируемая функция создаст store при первом использовании, но в дальнейшем будет просто возвращать уже существующий.
С другой стороны, функция createProductStore создаст store, задаст логику для метода addProduct и использует функцию logger, которую мы ей передаём. Этот logger, как вы, вероятно, уже догадались, — тот самый, который мы получили при использовании плагина Zustand.
Когда store готов, мы можем начать добавлять в него товары.
Добавление товаров в наш store
Section titled Добавление товаров в наш storeStore экспортирует метод addProduct, который отвечает за отслеживание товаров в нашей корзине.
Чтобы импортировать функцию в свой код, вам нужно:
- Импортировать и использовать провайдер контекста Tracker.
- Получить атрибут pluginsReturnedValue из контекста.
- Использовать его для вызова метода zustand (обратите внимание, что метод назван по значению атрибута name, заданному при настройке плагина выше), и передать строковый атрибут, чтобы дать store имя (это имя будет использоваться во время воспроизведения).
- Метод zustand вернёт logger, который мы будем использовать при вызове хука useProductStore из zustand (того, что мы создали для store).
Всё это кажется слишком сложным, но по сути всё сводится к следующему:
const { pluginsReturnedValues } = useContext(TrackerContext)
const useProductStoreTracked = useProductsStore(
pluginsReturnedValues.zustand('products_store')
)
const { addProduct } = useProductStoreTracked()
Теперь вы можете просто вызвать метод addProduct, и он добавит товары из корзины в store.
Чтение данных из store
Section titled Чтение данных из storeКак вы, вероятно, догадываетесь, если вы хотите прочитать данные из store Zustand, вам нужно выполнить тот же набор шагов. Но вместо того чтобы брать метод addProduct, мы деструктурируем массив products.
Вот так:
const { pluginsReturnedValues } = useContext(TrackerContext)
const useProductStoreTracked = useProductsStore(
pluginsReturnedValues.zustand('products_store')
)
const { products } = useProductStoreTracked()
Затем вы можете обычным образом перебирать товары:
<div>
{products.map((p: Product, idx: Number) => {
return (
<div key={+idx}>
{p.name}({p.amount})
</div>
)
})}
</div>
Приведённый выше код перебирает список товаров и отображает их на экране. Каждый раз, когда вы добавляете в store ещё один товар, он также будет обновляться здесь.
Синхронизация состояния с session replay
Section titled Синхронизация состояния с session replayЧтобы просмотреть изменения состояния во время воспроизведения, просто нажмите на новую вкладку Zustand в правом нижнем углу:

При нажатии на неё вы увидите содержимое store и сможете понять, как оно меняется, а также какие данные в нём сохраняются:

Обратите внимание на имя store: это на самом деле то имя, которое мы использовали при первом вызове метода zustand.
Есть вопросы?
Section titled Есть вопросы?Если вы используете не Next.js, а другой фреймворк, способ использования должен быть похожим; ключевым является то, как вы создаёте store. Пока вы находите способ использовать функцию logger при его создании, вы сможете отслеживать состояние во время воспроизведения.
Вы можете ознакомиться с этим репозиторием, чтобы увидеть полный исходный код рабочего приложения Next.js с плагином Zustand.
Если у вас возникнут какие-либо проблемы с настройкой плагина Zustand в вашем проекте, свяжитесь с нами в нашем сообществе Slack и задайте вопросы напрямую нашим разработчикам!