Tarjima qoshish uchun havola boyicha o'tib Pull Request oching (havolaga o'tish).
Standart til uchun tarkibni ko'rsatadi.
Dynamic models
At the moment dynamic models are still under development, their API may change over time. This article is for informational purposes only, and we strongly do not recommend using this functionality in production.
NOT RECOMMENDED FOR PRODUCTION USE.
Currently effector does not support creating units dynamically; units must be defined statically at the module level. If units are created at runtime, a memory leak will occur because units will remain in the graph forever. Although you can try using withRegion
, createNode
, and clearNode
, this requires developer expertise, since these are low-level APIs, and moreover you will have to track the unit lifecycle yourself, which can be a headache.
Therefore, for cases where dynamics were needed, key-value stores were used, storing objects where keys were identifiers and values were states, for example:
import { createStore, createEvent } from "effector";import { useStoreMap } from "effector-react";
type Item = { id: string; count: number };const $items = createStore<Record<string, Item>>({});
const addItem = createEvent<Item>();const removeItem = createEvent<string>();
$items.on(addItem, (state, item) => ({ ...state, [item.id]: item,}));
$items.on(removeItem, (state, id) => { const copy = { ...state }; delete copy[id]; return copy;});
In the UI, useStoreMap
was used to subscribe only to the part that corresponds to id
to get the data:
import { $items, addItem, removeItem } from "./model";import { useStoreMap, useUnit } from "effector-react";
function Counter({ id }: { id: string }) { const item = useStoreMap({ store: $items, keys: [id], fn: (state, [key]) => state[key], });
const [onAddItem, onRemoveItem] = useUnit([addItem, removeItem]);
if (!item) return null;
return ( <div> <span>{item.count}</span> <button onClick={() => onAddItem({ id, count: item.count + 1 })}>+</button> <button onClick={() => onRemoveItem(id)}>Delete</button> </div> );}
Although this approach works, it is not very convenient, especially if the structure is more complex than in this example.
Models introduce a new way to work with dynamic states, allowing you to create model instances on the fly that have their own states and logic.
Setup and working with models
Currently models are implemented in a separate repository and available as a separate package:
npm install @effector/model
and also a package for React integration:
npm install @effector/model-react
In the root of the repository you can find the apps
directory with examples of model usage in applications with near-real functionality. In this article we will just get familiar with the API and what dynamic models look like.
Model API
Dynamic models introduce a set of new APIs:
-
keyval
β an operator that creates a collection of model instances, where each element is identified by a key. Dynamic creation and deletion of model instances happens viakeyval
. It can also be used inside anotherkeyval
for nested structures. It expects a callback that returns an object with the following properties:state
β the model state, an object containing stores or anotherkeyval
model. One of the properties must also serve as the model keykey
β the model key, i.e. its unique identifierapi
β an optional object with events or effects for working with the modelonMount
β an optional event or effect triggered when a model instance is createdoptional
β an optional array of strings representing non-required fields of the model at creation
Example:
export const restaurantsList = keyval(() => { const $name = createStore(""); const $description = createStore(""); const $category = createStore<string[]>([]);
const dishesList = keyval(() => { const $name = createStore(""); const $description = createStore(""); const $price = createStore(0); const $additives = createStore<Additive[]>([]);
return { key: "name", state: { name: $name, description: $description, price: $price, additives: $additives, }, optional: ["additives"], }; });
return { key: "name", state: { name: $name, description: $description, category: $category, dishes: dishesList, }, api: { addDish: dishesList.edit.add, removeDish: dishesList.edit.remove, }, optional: ["category", "dishes"], };});
Now using restaurantsList
we can add, update, or remove model instances at runtime.
const addRestaurant = createEvent();
sample({ clock: addRestaurant, fn: () => ({ name: "Starbucks", description: "American corporation and the largest coffeehouse chain in the world", }), target: restaurantsList.edit.add,});
lens
β lens is needed to dive inside akeyval
for working with data. For example, with nestedkeyval
we can access data or API from the very top to the very bottom:
const menuItemIdLens = lens(orderKeyval).item(orderId).menuItemId;const foodDescLens = lens(restaurantKeyval).item(restId).menu.item(menuItemIdLens).description;
At the moment the lens API is still being refined and may differ from what is shown in the repository examples.
In addition to the main effector package, there is also an API for effector-react to conveniently work with models in React:
useEntityList(keyval, View)
β hook that takeskeyval
as the first argument and a component as the second. Iterates over all keys in the collection and for each creates anEntityProvider
, passingView
into it. Simply put, itβs a way to render a list and later work with other hooks without passingid
.useEntityItem(keyval, key?)
β returns an entity byid
in akeyval
collection. Ifkey
is explicitly provided, it searches for the element by this key, if not provided, it tries to get it from the nearestEntityProvider
.useItemApi(keyval, key?)
β returns the entity API object for working with it.useEditItemField(keyval, key?)
β returns an object with functions for updating each model field. Ifkey
is explicitly provided, it searches for the element by this key, if not provided, it tries to get it from the nearestEntityProvider
.useEditKeyval(keyval)
β returns an object of methods for modifying the model, such as add, delete, or update.
const { add, map, remove, replaceAll, set, update } = useEditKeyval(ordersList);
Related API and docs
-
API
clearNode
β Method for destroying unitswithRegion
β Method to set region for units
-
Articles
Ingliz tilidagi hujjatlar eng dolzarb hisoblanadi, chunki u effector guruhi tomonidan yozilgan va yangilanadi. Hujjatlarni boshqa tillarga tarjima qilish jamiyat tomonidan kuch va istaklar mavjud bo'lganda amalga oshiriladi.
Esda tutingki, tarjima qilingan maqolalar yangilanmasligi mumkin, shuning uchun eng aniq va dolzarb ma'lumot uchun hujjatlarning asl inglizcha versiyasidan foydalanishni tavsiya etamiz.