Closed filipjnc closed 5 years ago
@filipjnc can you please provide a test project that demonstrates what you want to achieve?
Here you go: https://stackblitz.com/edit/react-7nrqcn
The error happens when I construct the selector in store2.js
:
const { posts } = useStore(store1);
The example makes very little sense, but in a larger application the stores must interact to derive state (like in Reselect for Redux). Thanks for any tips how to get this working without unexpected side-effects!
@filipjnc this unfortunately won't work with the current way outstated is written.
useStore
relies on existence of StateContext
- and this is something that's not present during init.
It should be possible to rewrite outstated Provider
to account for that, but I'm not sure it's worth it.
I've been thinking about the case of accessing one store from another and to be honest I don't see any valid cases so far.
E.g. for the example you gave - IMO the second store should be a part of the first once since they are logically related.
If you have more convincing examples - would love to see them.
Say you have a store where you persist raw data coming in:
posts: {
1: {
"id": 1,
"title": "Post 1"
},
2: {
"id": 2,
"title": "Post 2"
},
}
Then in another store you have stuff like activePostId: 1
based on user interaction. I need a computed/derived property activePost = activePostId ? posts[activePostId] : null
, which is shared across different components.
Maybe it is possible to create a hook that provides the user the state (or a slice of it) with the current values in it? Easy Peasy does something similar: https://easy-peasy.now.sh/docs/tutorial/accessing-state.html
Why would activePostId
be in a different store? That's what I don't quite understand.
The way it makes sense to structure this to me is:
import { useState } from 'react';
const store = () => {
const [activePostIndex, setActivePostIndex] = useState(0);
const [posts, setPosts] = useState([
'Post 1',
'Post 2',
'Post 3'
]);
const activePost = useMemo(
() => posts[activePostIndex],
[posts, activePostIndex]
);
return { activePostIndex, setActivePostIndex, posts, setPosts };
};
export default store;
What's the point of splitting it? 🤔
I guess I will have to merge more stores. It was just more readable when I splitted the data store from the one holding user interaction stuff. Thanks for your insights!
@filipjnc if you really want to use multiple stores, I'd encourage you to explore alternative solution, e.g. you could do this with unstated-next - like so
@yamalight I don't like unstated-next for its container callback hell. There are other solutions like easy-peasy but I prefer the redux architecture for much larger apps.
A good solution for outstated that I found in the meantime is to create custom react hooks for these composed selectors:
function useActiveFile() {
const { activeFileIndex } = useStore(uiStore);
const { files } = useStore(dataStore);
const activeFile = useMemo(() => files[activeFileIndex], [files, activeFileIndex]);
return { activeFile };
}
Maybe you could include this tip in the docs for those who initially feel lost about composed selectors and tend to forget what React offers out of the box :)
@filipjnc this looks pretty neat! would appreciate a PR with this :)
Hi, how would you create selectors in a store with values from another store?
When I put
useStore
in another store I get an error that it should be wrapped in a<Provider>
.Thanks!