Reducer — часть глобального состояние приложения, в котором описывается как состояние будет изменяться. У reducer есть действия, c помощью которых, приложение, меняет свое состояние. Типичный reducer в redux представляет собой файл с импортом констант или action creators, начальным состоянием reducer, функциями-помощниками, и самим reducer.
Например:
//books.reducer.js
import { ADD_BOOK, DELETE_BOOK, EDIT_BOOK, GET_BOOKS } from 'constants/actionTypes/book';
import mockedBooks from 'mocks/books';
const initState = {
books: [],
};
function addBook(booksList, book) {
return [...booksList, book];
}
function deleteBook(booksList, bookID) {
return booksList.filter((book) => book.id !== bookID);
}
function editBook(booksList, editedBook) {
return booksList.map((book) => {
if (book.id === editedBook.id) {
return { ...book, ...editedBook };
}
return book;
});
}
export function booksReducer(state = initState, action) {
switch (action.type) {
case GET_BOOKS: {
return {
books: mockedBooks,
};
}
case ADD_BOOK: {
return {
...state,
books: addBook(state.books, action.payload.book),
};
}
case DELETE_BOOK: {
return {
...state,
books: deleteBook(state.books, action.payload.id),
};
}
case EDIT_BOOK: {
return {
...state,
books: editBook(state.books, action.payload.book),
};
}
default: {
return state;
}
}
}
При замене redux на effector возникает вопрос переписывание одних сущностей на другие. Проведем аналогию:
Модель — описание сценария или бизнес-логики приложения. Модель может включать в себя другие модели. В модели можно создавать ивенты, эффекты, хранилища состояний и описывать логику взаимодействия.
// books.model.js
import { createEffect, createStore, createEvent } from 'effector';
import mockedBooks from 'mocks/books';
function handleAddBook(books, book) {
return [...books, book];
}
function handleDeleteBook(books, bookID) {
return books.filter((book) => book.id !== bookID);
}
function handleEditBook(books, editedBook) {
return books.map((book) => {
if (book.id === editedBook.id) {
return { ...book, ...editedBook };
}
return book;
});
}
function noop() {}
/**
* Это модель - файл описывающий сущности, реакции, и связи между ними.
* Ивент описывается как "что произошло", and returns a new state value.
* A reducer's function signature is: (state, action) => newState
*
* The Redux state should contain only plain JS objects, arrays, and primitives.
* The root state value is usually an object. It's important that you should
* not mutate the state object, but return a new object if the state changes.
*
* You can use any conditional logic you want in a reducer. In this example,
* we use a switch statement, but it's not required.
*/
export const $books = createStore([]);
const fxGetBooks = createEffect({ handler: () => Promise.resolve(mockedBooks) });
export const getBooks = fxGetBooks.prepend(noop);
export const editedBook = createEvent();
export const addedBook = createEvent();
export const deletedBook = createEvent();
$books
.on(fxGetBooks.doneData, (_, books) => books)
.on(editBook, handleEditBook)
.on(addBook, handleAddBook)
.on(deleteBook, handleDeleteBook);
booksReducer меняем на создание Store, где в вызове функции createStore
аргументом задаем начальное состояние (default state).
- const initState = { books: [] };
- export function booksReducer(state = initState, action) {}
+ export const $books = createStore([])
Action type меняем на Event.
- export const ADD_BOOK = 'ADD_BOOK';
+ export const addBook = createEvent();
Switch case меняем на .on
- switch (action.type) {
- case ADD_BOOK: {
- return {
- ...state,
- books: addBook(state.books, action.payload.book),
- };
- }
+$books.on(addBook, handleAddBook)