So what is Effector ☄️ ?
Tags: typescript, javascript, effector, webdev
Published: 2022-12-10 00:15:25

Nowadays, frontend applications build with using [redux(rtk)](https://redux-toolkit.js.org/)/[mobx](https://mobx.js.org/README.html) state-managers because they modern and hype trends.

[**Effector**](https://effector.dev), it is the another way to create state and business logic for your frontend application.  

In this article, I just want to introduce you with effector!

## ⚙️ How to use

Effector has three main units: **stores**, **effects**, **events**.
Seems simple? But not everything is as simple as it seems🙂

### ☄️ [Stores](https://effector.dev/docs/api/effector/store)

The **Store** is an object which stores the state value.
You can create store using `createStore(initialState)`
  ```ts
const $store = createStore(1);
```
Now we have `$store` with numeric state, which has value `1`

### ☄️ [Events](https://effector.dev/docs/api/effector/event)

The **Event** is a simple function with one argument which returns this argument, but also this unit prepared for another effector operations (will be mentioned below). Better to think that this is intention to change the state.  

In general there are two types of events:  
 - something happened on UI, e.g. `loginButtonPressed`, `inputValueChanged`  
 - Event which changes the state, e.g. `loginInUser`, `changeInputValue`  

You can create event using `createEvent(name?)`
  ```ts
const changeStore = createEvent<number>()
```
Now we have `changeStore` event with numeric payload.  
Let's create a bit more events for our example

```ts
const incrementButtonPressed = createEvent()
const decrementButtonPressed = createEvent()
```

### ☄️ [Effects](https://effector.dev/docs/api/effector/effect)

The **Effect** is a container for async function. If we compare it with [Redux Toolkit](https://redux-toolkit.js.org/), we can relate this unit to async thunk.

Effects in Effector are used to create and handle async operations or side effects

Effects should be used for impure actions, e.g. **AJAX**, working with localStorage, some code which can throw an exception.
In general, you will use effects for making requests.

You can create effect using `createEffect(handler)`
  ```ts
const sendStateToServerFx = createEffect(async (state: number) => {
  const response = await fetch('/server', {
    method: 'post',
    body: state
  })
})
```
Now we have `sendStateToServerFx` effect with numeric payload

### Let's to sum up that we had managed to create

  ```ts
const $store = createStore(1);
const changeStore = createEvent<number>();
const incrementButtonPressed = createEvent()
const decrementButtonPressed = createEvent()
const sendStateToServerFx = createEffect(async (state: number) => {
  const response = await fetch('/server', {
    method: 'post',
    body: state
  })
})
```

## How to connect it all together ?

Effector has a lot of methods to work with data flow, but in this article we will try to use only one [`sample` method](https://effector.dev/docs/api/effector/sample)

```ts
import { sample } from "effector"
```

**`sample`** it is universal multipurpose method to work with data flow

Now we need to put value from `changeStore` payload to `$store` store
  ```ts
sample({
  source: changeStore,
  target: $store,
})
```
This operation says "when **source** will be called, take value from **source** and send it to **target**"

Now if we call `changeStore(100)` then `$store` will have value `100`   in state

Now we need send `$store` value to server when it will be changed

  ```ts
sample({
  source: $store,
  target: sendStateToServerFx,
})
```

Two samples, but what if we can create only sample ? Let's try
  ```ts
sample({
  source: changeStore,
  target: [sendStateToServerFx, $store],
})
```

But what if we need to prevent this changes when `sendStateToServerFx` is in pending state (request is calling/response is fetching)

```ts
sample({
  source: sendStateToServerFx.pending,
  clock: changeStore,
  filter: (pending, value) => !pending,
  fn: (pending, value) => value,
  target: sendStateToServerFx,
})
```
This operation says "when **clock** will be called, take value from **source** and send it to the **filter**. If **filter** returns `true` then call **fn** and returned value from **fn** send to **target**, otherwise skip **fn** and **target** steps"

Also we forget about `increment` and `decrement` events, let's connect them to our store  

```ts
sample({
  source: $store,
  clock: incrementButtonPressed,
  fn: (state) => state + 1,
  target: changeStore,
})

sample({
  source: $store,
  clock: decrementButtonPressed,
  fn: (state) => state - 1,
  target: changeStore,
})

```

I think now `sample` looks a little more complicated than it used, but it is very powerful!
[Here is a link to effector playground to check this code](https://share.effector.dev/uLcUmdVi)

### So, let's connect this to React

  ```tsx
import { FC } from "react";
import { useUnit } from "effector-react";

const MyComponent: FC = () => {
  const state = useUnit($store)
  
  return (
    <div>
      <button onClick={() => decrementButtonPressed()}>
       -1
      </button>
      <span>
      {state}
      </span>
      <button onClick={() => incrementButtonPressed()}>
       +1
      </button>
    </div>
  )
}
```

Now we have made the basic counter with one specific thing - safety sending counter data to server.  
And React knows about events and data-to-render only, we don't need to create payload for events\effects inside React, because we can store this logic inside effector.


## 📦 What about size?

Core library package has **10.4KB** gzipped size ([bundlephobia](https://bundlephobia.com/package/effector@22.4.0))
![10.4KB gzipped size](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pc6e83karovr5lnjrthh.png)
React bindings package has **3.7KB** gzipped size ([bundlephobia](https://bundlephobia.com/package/effector-react@22.3.4))
![3.7KB gzipped size](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6mifm792lvb1n2v8ozd.png)


## Summarize

Effector has a lot of methods to create data-flow in your frontend application (attach, combine, merge, restore, guard, forward etc).

Using this library, you can declare all business logic for your frontend application. Even complex cases.

You can separate UI-logic from business logic with using this library.

Currently, many companies actively use the effector as data-flow\state manager in their own frontend applications.

I hope you will try this powerful tool ❤️

Thanks for reading, good luck!