An open API service indexing awesome lists of open source software.

https://github.com/evgenyifedotov/effector-reflect

☄️ Render react components by effector stores.
https://github.com/evgenyifedotov/effector-reflect

effector react

Last synced: about 1 year ago
JSON representation

☄️ Render react components by effector stores.

Awesome Lists containing this project

README

          

# Effector-reflect

☄️ Render react-components by effector stores.

## Install

### Npm

```sh
npm install effector-reflect
```

### Yarn

```sh
yarn add effector-reflect
```

## Motivation

### Common ui

```tsx
// ./ui.ts
import React, { FC, ChangeEvent, useCallback } from 'react';

type InputProps = {
value: string;
onChange: ChangeEvent;
};

export const Input: FC = ({ value, onChange }) => {
return ;
};
```

### Old case

```tsx
// ./old-case.ts
import React, { FC, ChangeEvent, useCallback } from 'react';
import { createEvent, restore } from 'effector';
import { useStore } from 'effector-react';

import { Input } from './ui';

// Model
const changeName = createEvent();
const $name = restore(changeName, '');

// Component
export const Name: FC = () => {
const value = useStore($name);
const changed = useCallback(
(event: ChangeEvent) => changeName(event.target.value),
[],
);

return ;
};
```

### New case

```tsx
// ./new-case.ts
import { createEvent, restore } from 'effector';
import { reflect } from 'effector-reflect';

import { Input } from './ui';

// Model
const changeName = createEvent();
const $name = restore(changeName, '');

// Component
export const Name = reflect({
view: Input,
bind: { value: $name, onChange: (event) => changeName(event.target.value) },
});
```

## Reflect

Method for bind stores to a view.

```tsx
// ./user.tsx
import React, { FC, useCallback, ChangeEvent } from 'react';
import { createEvent, restore } from 'effector';
import { reflect } from 'effector-reflect';

// Base components
type InputProps = {
value: string;
onChange: ChangeEvent;
placeholder?: string;
};

const Input: FC = ({ value, onChange, placeholder }) => {
return ;
};

// Model
const changeName = createEvent();
const $name = restore(changeName, '');

const changeAge = createEvent();
const $age = restore(changeAge, 0);

const inputChanged = (event: ChangeEvent) => {
return event.currentTarget.value;
};

// Components
const Name = reflect({
view: Input,
bind: {
value: $name,
onChange: changeName.prepend(inputChanged),
},
});

const Age = reflect({
view: Input,
bind: {
value: $age,
onChange: changeAge.prepend(parseInt).prepend(inputChanged),
},
});

export const User: FC = () => {
return (





);
};
```

## Create reflect

Method for creating reflect a view. So you can create a UI kit by views and use a view with a store already.

```tsx
// ./ui.tsx
import React, { FC, useCallback, ChangeEvent, MouseEvent } from 'react';
import { createReflect } from 'effector-reflect';

// Input
type InputProps = {
value: string;
onChange: ChangeEvent;
};

const Input: FC = ({ value, onChange }) => {
return ;
};

export const reflectInput = createReflect(Input);

// Button
type ButtonProps = {
onClick: MouseEvent;
title?: string;
};

const Button: FC = ({ onClick, children, title }) => {
return (

{children}

);
};

export const reflectButton = createReflect(Button);
```

```tsx
// ./user.tsx
import React, { FC } from 'react';
import { createEvent, restore } from 'effector';

import { reflectInput, reflectButton } from './ui';

// Model
const changeName = createEvent();
const $name = restore(changeName, '');

const changeAge = createEvent();
const $age = restore(changeAge, 0);

const submit = createEvent();

// Components
const Name = reflectInput({
value: $name,
onChange: (event) => changeName(event.target.value),
});

const Age = reflectInput({
value: $age,
onChange: (event) => changeAge(parsetInt(event.target.value)),
});

const Submit = reflectButton({
onClick: () => submit(),
});

export const User: FC = () => {
return (




Save left
Save right

);
};
```

## SSR

For SSR need to replace imports `effector-reflect` -> `effector-reflect/ssr`.
Also use `event.prepend(params => params)` instead `(params) => event(params)`.

```tsx
// ./ui.tsx
import React, { FC, useCallback, ChangeEvent, MouseEvent } from 'react';

// Input
type InputProps = {
value: string;
onChange: ChangeEvent;
};

const Input: FC = ({ value, onChange }) => {
return ;
};
```

```tsx
// ./app.tsx
import React, { FC } from 'react';
import { createEvent, restore, Fork, createDomain } from 'effector';
import { reflect } from 'effector-reflect/ssr';
import { Provider } from 'effector-react/ssr';

import { Input } from './ui';

// Model
export const app = createDomain();

export const changeName = app.createEvent();
const $name = restore(changeName, '');

// Component
const Name = reflect({
view: Input,
bind: { value: $name, onChange: changeName.prepend(event => event.target.value) },
});

export const App: FC<{ data: Fork }> = ({ data }) => {
return (



);
};
```

```tsx
// ./server.ts
import { fork, serialize, allSettled } from 'effector/fork';

import { App, app, changeName } from './app';

const render = async () => {
const scope = fork(app);

await allSettled(changeName, { scope, params: 'Bob' });

const data = serialize(scope);

const content = renderToString();

return `

${content}

window.__initialState__ = ${JSON.stringify(data)};


`;
};
```

## Roadmap

- [] Auto moving test from ./src to ./dist-test