npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

istore-react

v1.0.9

Published

lib for connecting istore with react app

Readme

istore-react

Библиотека для связывания react компонентов с istore доменами.

Данная библиотека позволяет "замкнуть" домен и получить функцию с помощью которой можно сформировать обертку над компонентом. Обертка позволяет будет брать часть данных и/или действий из домена и прокидывать их в оборачиваемый компонент в виде пропертей. Так же такие обертки будут автоматически перерисовывать компонент при изменении используемых данных домена. Пример применения данной библиотеки в связке с библиотекой istore можно посмотреть по ссылке https://github.com/Curnull/todo-istore

Пример

import { domain, value } from 'istore';
import { lockDomain } from 'istore-react';
import { Input } from './components';

const createUserDomain = domain({ // описываем модель данных
  name: value(''),
  age: value(0),
  email: value(''),
});

const wrap = lockDomain('createUserDomain', createUserDomain); // замыкаем домен с уникальным именем 'createUserDomain' и получаем функцию для оборачивания компонентов

const NameInput = wrap // начинаем цепочку оборачивания
  .withProps((state, methods) => ({ // описываем какие пропсы буду передаваться оборачиваемому компоненту
    value: state.name, // в качестве значения берем имя из состояния домена
    onChange: methods.name.set, // в качестве метода изменения имени, метод из методов домена для изменения имени
  }))
  .component(Input); // замыкаем цепочку компонентом

const AgeInput = wrap // повторяем операцию для поля возраст
  .withProps((state, methods) => ({
    value: state.age,
    onChange: methods.age.set,
  }))
  .component(Input);

const EmailInput = wrap //  повторяем операцию для поля почтовый ящик
  .withProps((state, methods) => ({
    value: state.email,
    onChange: methods.email.set,
  }))
  .component(Input);

const CreateUserForm = () => ( // создаем компонент который помещает все обернутые инпуты на форму
  <div>
    <div>name: <NameInput /></div>
    <div>age: <AgeInput /></div>
    <div> email: <EmailInput /><div>
  </div>
);

export default wrap.rootComponent(CreateUserForm); // оборачиваем компонент CreateUserForm как "главный", что бы при его маунте и анмаунте на страницу, домен помещал и удалял свое состояние из/в хранилище.

API

lockDomain(prefixProvider, domainProvider, extra)

Функция для создания экземпляра класса WrapChain который будет связан с определенным доменом.

Параметры

  • prefixProvider [required, string | (props: any) => string] - строка либо функция возвращающая строку и принимающая проперти "главного" компонента. Возвращенная строка будет использоваться как префикс при помещении состояния домена в хранилище (domain.mount(prefix)). Префикс должен быть уникальным в рамках всего приложения.

  • domainProvider [required, Domain | (props: any) => Domain] - экземпляр домена, либо функция возвращающая экземпляр домена на основе пропертей главного компонента.

  • extra [optional, Object] - объект вида (все свойства опциональны):

    • onMount: (domain, props) => void - функция которая будет вызвана при помещении главного компонента на страницу, в нее будет передан экземпляр домена и проперти главного компонента. Может быть использована для первичной инициализации состояния домена.
    • onChangeProps: (domain, nextProps, prevProps) => void - функция которая будет вызываться каждый раз при изменении "внешних" (т.е. пропертей приходящих из родительского компонента, но не из оберток) пропертей. Первый аргумент функции это экземпляр домена, второй объект с новыми пропертями, третий объект со старыми пропертями. Может использоваться для обновления состояния домена при изменении пропертей главного компонента.

Возвращаемое значение Экземпляр класса WrapChain связанный с переданным доменом.

WrapChain

Класс позволяющий с помощью набора методов вызывающихся последовательно друг за другом расширить react компонент, предоставляя для него определенные проперти, функции жизненного цикла и другие расширения. Так-же связывает react компоненты с какой-либо доменной моделью. Сформированный компонент автоматически отслеживает изменения доменной модели и автоматически перерисовывается когда это нужно (реагирует только на изменения тех полей в состоянии домена, который он использует для расчета своих пропертей). Все методы класса генерируют и возвращают новый экземпляр WrapChain на основе текущей конфигурации, что позволяет делать частично завершенные цепочки, который потом можно продолжить или объеденить.

Свойства отсутсвуют

Методы

  • withProps(propsProvider: (state, methods, extra) => Object): WrapChain - метод для предоставления пропертей для компонента который будет обернут цепочкой. Принимает функцию, в которую будет передано состояние домена, методы домена, и объект с вспомогательными функциями. propsProvider должен возвращать объект сформированный из полей параметров state и/или methods. Функция propsProvider будет вызываться каждый раз при обновлении используемых в ней полей объекта state. Входной объект extra имеет вид
    • getProps: () => any - функция, возвращающая текущие проперти оборачиваемого компонента.
    • or: (...args: any) => boolean - функция для выполнения логической операции "или" (см. Маппинг пропертей из состояния и методов домена)
    • and: (...args: any) => boolean - функция для выполнения логической операции "и" (см. Маппинг пропертей из состояния и методов домена) Пример
import { domain, value } from 'istore';
import { lockDomain } from 'istore-react';

const someDomain = domain({ ... })
const wrap = lockDomain('someDomain', someDomain);

const wrapChain = wrap.withProps((state, methods, { getProps }) => ({
  prop1: state.someValue,
  prop2: state.someObj.someValue,
  onSomething: methods.someValue.set,
  onSomethingElse: () => methods.someObj.someValue.delete(getProps().someId),
}))
  • onChangeProps(callback: (domain: Domain, nextProps: any, prevProps: any, isInit: boolean) => void): WrapChain - функция которая принимает коллбэк который будет вызываться при инициализации оборачиваемого компонента и при изменении его пропертей (внешник, т.е. не предоставляемых цепочкой с помощью .withProps). Описание параметров коллбэка:
    • domain [Domain] - экземпляр домена
    • nextProps [any] - объект с новыми пропертями компонента (будет опредено всегда, в случае с инициализацией компонента тут будут его изначальные проперти)
    • prevProps [any] - объект со старыми пропертями компонента (будет опредено только при обновлении пропертей, в случае с инициализацией компонента тут будет пустой объект)
    • isInit [boolean] - флаг который равен true если этот вызов был спровацированн инициализацией компонента (componentWillMount), false если произошло обновление пропертей (componentWillReceiveProps)
import { domain, value } from 'istore';
import { lockDomain } from 'istore-react';

const someDomain = domain({ ... })
const wrap = lockDomain('someDomain', someDomain);

const wrapChain = wrap.onChangeProps((domain, nextProps, prevProps, isInit) => {
  if (isInit) {
    console.log('component initialized')
  } else if (nextProps.someProp !== prevProps.someProp) {
    console.log('some prop changed');
    domain.methods.someValue.set(nextProps.someProp);
  }
})
  • withHOC(hoc: (component: Component) => Component): WrapChain - метод для дополнительного оборачивания компонента каким-либо HOC'ом.
import { domain, value } from 'istore';
import { lockDomain } from 'istore-react';

const someDomain = domain({ ... })
const wrap = lockDomain('someDomain', someDomain);

const myHoc = (value) => (Component) => (props) => <Component {...props} someProps={value} />

const wrapChain = wrap.withHOC(myHoc('example'))
  • lockSubDomain(stateProvider, methodsProveider: ): WrapChain - метод для создания нового экземпляра WrapChain, при этом домен этого экземпляра будет сформирован из текущего домена. Принимает 2 параметра:
    • stateProvider [required, (state: any) => any] - метод получающий состояние текущего домена и возвращающий состояние которое будет использоваться в новой цепочки в качестве состояния домена
    • stateProvider [required, (methods: any) => any] - метод получающий методы текущего домена и возвращающий методы которые будет использоваться в новой цепочки в качестве методов домена.

Замечание Цепочке полученной в резльтате функции lockSubDomain необходимо так-же указать главный компонент с помощью метода .rootComponent

import { domain, value } from 'istore';
import { lockDomain } from 'istore-react';
import { Input } from './components';

const someDomain = domain({ 
  someObj: {
    someObj: {
      someObj: {
        name: value('Example'),
      }
    }
  }
})
const wrap = lockDomain('someDomain', someDomain);

const subWrap = wrap.lockSubDomain(s => s.someObj.someObj.someObj, m => m.someObj.someObj.someObj);

const SomeInput = subWrap.withProps((state, methods) => ({
  value: state.name,
  onChange: methods.name.set,
}).component(Input);

// в случае если бы мы не делали lockSubDomain то обертка выглядела бы вот так
const SomeInput = wrap.withProps((state, methods) => ({
  value: state.someObj.someObj.someObj.name,
  onChange: methods.someObj.someObj.someObj.name.set,
}).component(Input);
  • join(chain: WrapChain): WrapChain - метод для объединения двух цепочек в одну. Принимает на входе цепочку для мержа и возвращает новый экземпляр WrapChain который сомещает конфигурацию из обоих цепочек.
import { domain, value } from 'istore';
import { lockDomain } from 'istore-react';
import { Input } from './components';

const someDomain = domain({ 
  name: value(),
})
const wrap = lockDomain('someDomain', someDomain);

const commonChain = wrap.withProps((state) => ({
  disabled: state.disabled,
}))

const NameInput = subWrap.join(commonChain).withProps((state, methods) => ({
  value: state.name,
  onChange: methods.name.set,
}).component(Input); // в итоге в компоннт Input попадут 3 проперти: value, onChange, disabled
  • сomponent(component: Component): Component - метод для для замыкания цепочки и получения обернутого компонента. Принимает на входе react компонент для обертки.

  • rootComponent(component: Component): Component - метод для оборачивания главного компонента домена, т.е. компонента при помещении которого на страницу домен должен поместить свое состояние в хранилищие, и удалить его из хранилища если компонент был удален со страницы.

wrap

Экземпляр класса WrapChain без привязки к какому либо домену. Можно использовать для добавления в компоннты статических пропертей

import { domain, value } from 'istore';
import { wrap } from 'istore-react';
import { Input } from './components';

const SomeReadonlyInput = wrap.withProps((state, methods) => ({
  value: 'static text',
  disabled: true,
}).component(Input);

Детали работы

Маппинг пропертей из состояния и методов домена

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

  1. При помещении обернутого компонента на форму происходит вызов всех маппероов (.withProps может быть сколько угодно в рамках одной цепочки)
  2. При первом вызове маппера происходит подписка на все экземпляры юнитов, состояния которых были использованы при формаировании пропертей.
  3. При изменения стейта любого из юнитов, состояния которых использовались для формарования пропертей, происходит повторный вызов всех мапперов в которых использовалось его состояние (таких мапперов может быть нескольких в рамках одной цепочки). В итге формируется новый объект с пропертями.
  4. Все вновь полученные проперти проверяются на предмет того, изменились ли они по сравнению с прошлым разом, и есть хотя бы она пропертя изменилась происходит перерисовка обернутого компонента уже с новыми пропертями.

Нюансы

Подписка

Подписка на юниты происходит только после первого вызова маппера, поэтому если обращения к state не произошло, то и подписки к юниту не будет, пример:

import { domainm value } from 'istore';
import { lockDomain } from 'istore-react'

const myDomain = domain({
    isActive: value(true),
    showName: value(false),
    name: value('John'),
})

const wrap = lockDomain('myDomain', myDomain);

const WrappedComponent = wrap
    .withProps((state) => ({
        name: state.showName && state.isActive ? state.name : ''
    }))
    .component(SomeComponent);

в примере выше если на момент первого вызова маппера в state.showName будет false, то WrappedComponent будет реагировать только на изменение стейта юнита который хранит значение state.isActive, но не будет реагировать на изменения состояния юнита state.name и state.isActive, что не верно. Что произошла подписка на все юниты нужно переписать маппер следующим образом:


const WrappedComponent = wrap
    .withProps(({ showName, isActive, name}) => ({
        name: showName && isActive ? name : ''
    }))
    .component(SomeComponent);

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

Если способ с деструктуризацией вам не походит, то есть еще 2 способа:

  1. Достать из объекта state все нужные для вычисления свойства в локальные перменные, и только затем произвести вычисления. Фактически это то же самое что и деструктуризация, только более наглядно.
  2. Использовать вспомогательные фукнции для логических операций or и and, пример:

const WrappedComponent = wrap
    .withProps((state, methods, { and }) => ({
        name: and(state.showName, state.isActive) ? state.name : ''
    }))
    .component(SomeComponent);

Передача функций в .withProps

Для удобства^ поля функции с одинаковыми названиями не перетирают друг друга, а объединяются в одну функцию, пример

import { wrap } from 'istore-react';

const WrappedComponent = wrap
    .withProps(() => ({
        onChange: () => console.log('on change')
    }))
    .withProps(() => ({
        onChange: () => alert('on change')
    }))
    .component(SomeComponent);

В данном примере мы имеем функцию onChange в двух мапперах переданных в .withProps, что вводит в ступор. С помощью внутреннего миханизма обединения функций с одинковыми названиями когда компонент SomeComponent вызовет функцию onChange из своих props, будут вызваны обе функции из .withProps, что даст строку в консоли и браузерный алерт. В то же время данный вариант приведет к ошибке:

import { wrap } from 'istore-react';
const WrappedComponent = wrap
    .withProps(() => ({
        onChange: () => console.log('on change')
    }))
    .withProps(() => ({
        onChange: 15
    }))
    .component(SomeComponent);

В примере выше мы пытаемся обернуть компонент используя два маппера, один из которыз возвращает функцию по ключу onChange а второй возвращает значение по тому же ключу. В таких случая в библиотеке будет выброшено исключени с описание проблемы. Более того, если компонент из мапперов получит несколько функций под одним ключем и хотя бы одна из них вернет значение отличное от undefined после ее вызова то будет выбрашено исключение. Таким образом под одним ключем могут объединяться только функции возвращающие undefined. Данная функциональность позволяет вешать несколько обработчиков на одно и то же событие (например onChange, onBlur, onFocus).