factories
In Effector's world any factory is a function that returns a set of Stores, Events or Effects. It's a way to encapsulate some logic and reuse it in different places.
If your application has any unit-tests or meant to be rendered on the server (SSR) factories have to be added to factories
field in config of effector/babel-plugin
or @effector/swc-plugin
. The reasons of this limitation are described in this article.
In real world it is easy to add any third-party library that uses factories to the config because it has an exact import path. But adding factories from your own code is a bit more complicated. There are no automatic ways to validate that all factories are added to the config. This library is solving this problem: just add @withease/factories
to the config and use it to create and invoke factories.
Also, this library covers a few edge-cases that are really important for SSR. To learn more about them, read the motivation.
Installation
First, you need to install package:
pnpm install @withease/factories
yarn add @withease/factories
npm install @withease/factories
Second, you need to setup effector/babel-plugin
or @effector/swc-plugin
. Please follow the instructions in the corresponding documentation.
That's it! Now you can use @withease/factories
to create and invoke factories across your application.
API
createFactory
To create a factory you need to call createFactory
with a factory creator callback:
import { createStore, createEvent, sample } from 'effector';
import { createFactory } from '@withease/factories';
const createCounter = createFactory(({ initialValue }) => {
const $counter = createStore(initialValue);
const increment = createEvent();
const decrement = createEvent();
sample({
clock: increment,
source: $counter,
fn: (counter) => counter + 1,
target: $counter,
});
sample({
clock: decrement,
source: $counter,
fn: (counter) => counter - 1,
target: $counter,
});
return {
$counter,
increment,
decrement,
};
});
invoke
Anywhere in your application you can invoke a factory by calling invoke
with a factory and its arguments:
WARNING
You have to invoke factories only in the top-level of your application. It means that you must not invoke it during component rendering or in any other place that can be called multiple times. Otherwise, you will get a memory leak.
This limitation is applied to any factory, not only to factories created with @withease/factories
.
import { invoke } from '@withease/factories';
const { $counter, increment, decrement } = invoke(createCounter, {
initialValue: 2,
});
Now we can use $counter
, increment
, and decrement
in our components. Here is how you might use them in different UI frameworks:
Example usage in React
import { useUnit } from 'effector-react';
import { $counter, increment, decrement } from './model'; // assuming you've invoked your factory in `model.js`/`model.ts`
const CounterComponent = () => {
const counter = useUnit($counter);
const [onIncrement, onDecrement] = useUnit(increment, decrement);
return (
<div>
<p>Counter: {counter}</p>
<button onClick={() => onIncrement()}>Increment</button>
<button onClick={() => onDecrement()}>Decrement</button>
</div>
);
};
Example usage in Vue
<template>
<div>
<p>Counter: {{ counter }}</p>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
</div>
</template>
<script setup>
import { useUnit } from 'effector-vue/composition';
import { $counter, increment, decrement } from './model'; // assuming you've invoked your factory in `model.js`/`model.ts`
const counter = useUnit($counter);
</script>