easy-peasy
easy-peasy copied to clipboard
Documentation make no sense. (Typescript)
Followed this: https://easy-peasy.vercel.app/docs/tutorials/typescript.html
then end-up like this
interface Todo {
text: string;
done: boolean;
}
interface StoreModel {
todos: Todo[];
}
interface TodosModel {
todos: Todo[];
completedTodos: Computed<TodosModel, Todo[]>;
addTodo: Action<TodosModel, Todo>;
saveTodo: Thunk<TodosModel, Todo>;
}
const store = createStore<StoreModel>({
todos: [],
completedTodos: computed((state) => state.todos.filter((todo) => todo.done)),
addTodo: action((state, payload) => {
state.todos.push(payload);
}),
saveTodo: thunk(async (actions, payload) => {
const result = await axios.post('/todos', payload);
actions.addTodo(result.data);
}),
});
export default store;
which look like this https://prnt.sc/C-FuQtxZDvpU then: https://prnt.sc/ZO6_XK27F_D-
I still can't figure out what is the issue. I see one issue is the documentation.
** "easy-peasy": "^5.0.4"
"typescript": "^4.6.4"
on PHPStorm 2022.1
Yeah, this is bad documentation. Soz.
@apuatcfbd If you're going to have multiple "slices" in your store, you can do something like this:
interface Todo {
text: string;
done: boolean;
}
interface StoreModel {
todos: TodosModel;
// ...another slice here
}
interface TodosModel {
todos: Todo[];
completedTodos: Computed<TodosModel, Todo[]>;
addTodo: Action<TodosModel, Todo>;
saveTodo: Thunk<TodosModel, Todo>;
}
const store = createStore<StoreModel>({
todos: {
todos: [],
completedTodos: computed((state) => state.todos.filter((todo) => todo.done)),
addTodo: action((state, payload) => {
state.todos.push(payload);
}),
saveTodo: thunk(async (actions, payload) => {
const result = await axios.post('/todos', payload);
actions.addTodo(result.data);
}),
}
// ...another slice here
});
Or if your store is going to be flat:
interface Todo {
text: string;
done: boolean;
}
interface StoreModel {
todos: Todo[];
completedTodos: Computed<StoreModel, Todo[]>;
addTodo: Action<StoreModel, Todo>;
saveTodo: Thunk<StoreModel, Todo>;
}
const store = createStore<StoreModel>({
todos: [],
completedTodos: computed((state) => state.todos.filter((todo) => todo.done)),
addTodo: action((state, payload) => {
state.todos.push(payload);
}),
saveTodo: thunk(async (actions, payload) => {
const result = await axios.post("/todos", payload);
actions.addTodo(result.data);
})
});
Either setup should fix your type errors.
Attempted to clarify the TS example in #770
@apuatcfbd If you're going to have multiple "slices" in your store, you can do something like this:
interface Todo { text: string; done: boolean; } interface StoreModel { todos: TodosModel; // ...another slice here } interface TodosModel { todos: Todo[]; completedTodos: Computed<TodosModel, Todo[]>; addTodo: Action<TodosModel, Todo>; saveTodo: Thunk<TodosModel, Todo>; } const store = createStore<StoreModel>({ todos: { todos: [], completedTodos: computed((state) => state.todos.filter((todo) => todo.done)), addTodo: action((state, payload) => { state.todos.push(payload); }), saveTodo: thunk(async (actions, payload) => { const result = await axios.post('/todos', payload); actions.addTodo(result.data); }), } // ...another slice here });
Or if your store is going to be flat:
interface Todo { text: string; done: boolean; } interface StoreModel { todos: Todo[]; completedTodos: Computed<StoreModel, Todo[]>; addTodo: Action<StoreModel, Todo>; saveTodo: Thunk<StoreModel, Todo>; } const store = createStore<StoreModel>({ todos: [], completedTodos: computed((state) => state.todos.filter((todo) => todo.done)), addTodo: action((state, payload) => { state.todos.push(payload); }), saveTodo: thunk(async (actions, payload) => { const result = await axios.post("/todos", payload); actions.addTodo(result.data); }) });
Either setup should fix your type errors.
Need slices in different file, there're many of them
@apuatcfbd Have you figured out how to setup slices in different files? This is possible. It's also possible to define each thunk, action, computed prop, etc. in a different file if you prefer that kind of organization. If you'd like an example of how to do slices this way, let me know and I can share an example.
@apuatcfbd Have you figured out how to setup slices in different files? This is possible. It's also possible to define each thunk, action, computed prop, etc. in a different file if you prefer that kind of organization. If you'd like an example of how to do slices this way, let me know and I can share an example.
We're open to PRs for more examples, so feel free to chuck one in there 👍
I'm currently working on adding some more (#773)
@apuatcfbd Have you figured out how to setup slices in different files? This is possible. It's also possible to define each thunk, action, computed prop, etc. in a different file if you prefer that kind of organization. If you'd like an example of how to do slices this way, let me know and I can share an example.
We're open to PRs for more examples, so feel free to chuck one in there 👍
I'm currently working on adding some more (#773)
An example would be helpful for me & others too.
@jmyrland Ok, cool - I can work on one for multiple slices and how to organize across several files. May take a bit for me to put it together but I'll def get on it.
In the meantime @apuatcfbd, consider this folder structure:
For this, we can set up our slices and our store like this:
// app/slices/todo/index.ts
import * as actions from "./actions";
import * as computed from "./computed";
import * as thunks from "./thunks";
export interface Todo {
text: string;
done: boolean;
}
type State = {
todos: Todo[]
}
const initialState: State = {
todos: []
};
const todoModel: TodoModel = {
...initialState,
...actions,
...thunks,
...computed,
};
export type TodoState = State;
export type TodoModel = TodoState &
typeof actions &
typeof thunks &
typeof computed;
export default todoModel;
// app/store.ts
import { State, createStore, createTypedHooks } from "easy-peasy";
import todo, { TodoModel } from "./slices/todo";
export type StoreModel = {
todo: TodoModel;
// ...more slices here
};
export type RootState = State<StoreModel>;
export const { useStoreActions, useStoreState } =
createTypedHooks<StoreModel>();
const store = createStore<StoreModel, RootState, Dependencies>({
todo,
// ... more slices here
});
export default store;
And in actions, thunks, computed, etc.:
// app/slices/todo/actions.ts
import { Action, action } from "easy-peasy";
import { Todo, TodoModel } from ".";
export const addTodo: Action<TodoModel, Todo> = action((state, payload) => {
state.todos.push(payload);
});
// ...more actions
Let me know if this makes sense. I will try to throw together a codesandbox at some point. You can also go a step further if you have many actions / thunks / computed props and put them all in individual files and export them all from an index file (e.g. actions
becomes a directory with an index file and all actions in the directory are exported from there so you can still do import * as actions from "./actions";
and get the type required for slice model).
@jmyrland Sounds like you have lots of easy-peasy apps in prod, do you have a different approach or do you mostly have flat stores or slices defined in a single file?
@jmyrland Ok, cool - I can work on one for multiple slices and how to organize across several files. May take a bit for me to put it together but I'll def get on it.
That would be awesome. Take a look at #773 if you need inspiration or a project template.
Let me know if this makes sense. I will try to throw together a codesandbox at some point. You can also go a step further if you have many actions / thunks / computed props and put them all in individual files and export them all from an index file (e.g. actions becomes a directory with an index file and all actions in the directory are exported from there so you can still do import * as actions from "./actions"; and get the type required for slice model).
Nice @no-stack-dub-sack ! Your examples look really neat 👍 I think this setup would work great, especially for big slices/stores.
@jmyrland Sounds like you have lots of easy-peasy apps in prod, do you have a different approach or do you mostly have flat stores or slices defined in a single file?
We use multiple slices (we call them nested stores/sub-stores), even up to 3-4 levels deep. Our slices are primarily in a single file - as the slices themselves aren't that big.
Because of our usecase, we treat models for each section a bit like "css modules" - we want them to live along side the component. So typically we have a Component.tsx
and a Component.model.ts
for the store model related to the component. This basically means that our file structure basically mirrors our state object.
All these component models are then nested into slices and referenced in our main model.ts
.
That's the gist of it. It's a bit tricky to exemplify, but I'll think of some way to make an example of this when I got some spare time.
Btw, this model uses slices/nested stores & store generators.
Nice @no-stack-dub-sack ! Your examples look really neat 👍 I think this setup would work great, especially for big slices/stores.
@jmyrland Thanks, yeah, we've found that this works well for us and our use-case. In our approach our components all generally map to a use-case / functionality represented by a logical state slice.
Because of our usecase, we treat models for each section a bit like "css modules"...
Sounds like an interesting approach! I suppose this is all closed source? When you say sub-store, though, you still only have one top-level call to createStore
, like in the example you linked to right? i.e. you can still access all of your nested models via a single useStoreState
hook.
Also, I initially thought you meant adding an additional section the docs tutorial section, but now I see you mean adding an example project. This may take me a bit more time to put together but I will still keep this on my todo list.
When you say sub-store, though, you still only have one top-level call to createStore, like in the example you linked to right? i.e. you can still access all of your nested models via a single useStoreState hook.
Correct 👍
Also, I initially thought you meant adding an additional section the docs tutorial section, but now I see you mean adding an example project. This may take me a bit more time to put together but I will still keep this on my todo list.
Oh I see 😅 sorry for the confusion.
Any help is appreciated 👏