Closed rmcarias closed 3 years ago
Good question. As a proxy object is a mutable variable. You can mutate anyways. I'd say it's out of the scope of the library implementation, but it's nice to have such recipes: https://github.com/pmndrs/valtio#recipes
One naive idea is something like this:
// countState.ts
// do not export the proxy object
const state = proxy({ count })
// getter (non reactive)
export const getCount = () => state.count
// hook (reactive)
export const useCount = () => useSnapshot(state).count
// action
export const increment = () => ++state.count
@dai-shi thank you for this recommendation. It makes sense since we are not using the flux pattern.
I have another question:
if I have a store that has something like:
{
animals:[],
setAnimals (animals) {
// assume it's a class
this.animals = animals;
}
}
// and in my react component I use it like so
import store from 'mystore';
function Component() {
useEffect(() => {
store.setAnimals(['zebra','horse','cats','dogs']);
},[]);
return <>
// I want to display the animals. Why should I ready from Snapshot vs just directly accessing 'store.animals'?
</>;
}
// I want to display the animals. Why should I ready from Snapshot vs just directly accessing 'store.animals'? // What is the difference between using the 'snapshot' and just accessing the prop directly?
If you directly access store.animals
, it won't trigger re-render.
It will be just like this.
const store = {
animals: [],
}
const Component = () => {
useEffect(() => {
store.animals = ['zebra','horse','cats','dogs']
}, [])
return <>{JSON.stringify(store.animals)}</>
)
@dai-shi Thanks for the feedback. So you are saying that in the above scenario, the store.animals acts like a useRef? I guess I am confused a bit because your examples have this:
setInterval(() => {
++state.count
}, 1000)
which mutates things directly
but also this:
// This will re-render on `state.count` change but not on `state.text` change
function Counter() {
const snap = useSnapshot(state)
return (
<div>
{snap.count}
<button onClick={() => ++state.count}>+1</button>
</div>
)
}
which mutates from snapshot. Which one is the one to use?
which mutates from snapshot
It doesn't mutate snapshot. It reads from snapshot. Inside onClick, it mutates state
.
Could you elaborate your confusion? Thanks. It's important for us to know how people read the docs.
@dai-shi I think I got it. I had to read the entire example again. When you referred to state.text and where you mention it will re-render on state.count
but I assume {snap.count}
is being watch and if a change happens it will re-render?
Meaning, can I rewrite the above as
`function Counter() {
return (
) }` and get the same as above?
Maybe it's just me, but an example of how useSnapshot and state translate "similarish" to React's ( I know it's not how it works but for those moving from this pattern to Proxy it would help)
const [state, setState] = useState()
...The docs don't have enough working examples of the usage combinations. 🤷🏼♂️
@dai-shi I think I got it. I had to read the entire example again. When you referred to state.text and where you mention it will re-render on
state.count
but I assume{snap.count}
is being watch and if a change happens it will re-render?
"{snap.count}
is being watch" is correct,
Meaning, can I rewrite the above as `function Counter() {
return (
{state.count} // 👈🏼 <button onClick={() => ++state.count}>+1
) }` and get the same as above?
and thus this is different, because {state.count}
isn't watch.
Maybe it's just me, but an example of how useSnapshot and state translate "similarish" to React's ( I know it's not how it works but for those moving from this pattern to Proxy it would help)
const [state, setState] = useState()
...The docs don't have enough working examples of the usage combinations. 🤷🏼♂️
valtio proxy is self-aware object, and you don't need a function like setState
update state.
If you prefer setState
style, I recommend use-immer
instead.
Would you elaborate explaining your use case please? Then, I think I can try creating code snippet, and hopefully we can improve docs.
@dai-shi I will create some examples. I have another question within this realm. I have this in a proxy file
Module: someotherproxystore
const anotherImportedProxyStore = proxy({uri:''});
export default anotherImportedProxyStore;
Module B:
import anotherImportedProxyStore from './someotherproxystore';
// this method is wrapped in a proxy
async loadItineraries(): Promise<string[]> {
/// code
const uri = anotherImportedProxyStore.uri; 👈🏼 //is this correct?
await somethingAsync();
return Promise.resolve([]);
}
My question is, how to you use other proxies from with other proxies correctly? If I just import another proxy object, and use it in a method of another module, is it automatically watched or updated (not sure if I have the correct verbiage here).
There's no magic behind functions/methods (unless we use this
, which is not recommended for beginners.)
// this method is wrapped in a proxy
It doesn't matter if a method is in a proxy or not.
const loadItineraries = async () => {
const uri = anotherImportedProxyStore.uri; 👈🏼 // this works, but it gets a string at evaluation once (meaning, not reactive)
await somethingAsync();
return Promise.resolve([]);
};
is it automatically watched or updated
So, no, it's not. What you are looking for is derive()
.
Closing as answered. Please open new issue or new discussion for further discussion.
How can I expose a proxy property as ready only and say allow only updates to happen through an action?