Closed mathieudutour closed 4 years ago
Trying it with Gatsby and it works quite nicely.
You need 3 files:
gatsby-browser.js
:
import React from 'react'
import { model } from './src/model'
const { Provider } = model.createStore({
initState: {
loadingUser: false,
},
initLocal: {
user: null,
},
})
export const wrapRootElement = ({ element }) => {
return <Provider>{element}</Provider>
}
gatsby-ssr.js
:
import React from 'react'
import { model } from './src/model'
const { Provider } = model.createStore({
initState: {
loadingUser: false,
},
// need `localFixture` because `localStorage` doesn't exist on server-side
localFixture: {
user: null,
},
})
export const wrapRootElement = ({ element }) => {
return <Provider>{element}</Provider>
}
gatsby-node.js
// Add Babel plugin
try {
require.resolve(`@prodo/babel-plugin`)
} catch (e) {
throw new Error(
`'@prodo/babel-plugin' is not installed which is needed by plugin '@prodo/gatsby-plugin'`
)
}
exports.onCreateBabelConfig = ({ stage, actions } /* , pluginOptions */) => {
actions.setBabelPlugin({
name: `@prodo/babel-plugin`,
stage,
})
}
And then you can use your store on any page.
I would also change to local-plugin
to make sure it doesn't crash when localStorage
doesn't exist (and print a nice warning).
You really need to write somewhere that the file where the model is needs to be called model
, I spent so much time trying to understand why everything was undefined
. Maybe instead of being undefined until the babel plugin change them, watch
and dispatch
could be functions that throws with a nice error message
I just now realised that it's all based on Proxy. As far as I know, babel can't polyfill Proxies. It's also only unavailable to more than ~8% of global users (which is a lot) 😕 https://caniuse.com/#search=Proxy
Thanks for the great feedback @mathieudutour! Very good point about mentioning that the model file needs to be called model
.
Maybe instead of being undefined until the babel plugin change them, watch and dispatch could be functions that throws with a nice error message
We have noted that using state
, watch
, and dispatch
incorrectly could result in a terrible error message (https://github.com/prodo-ai/prodo/issues/34). We have an experiemental ESLint plugin that will error when using state
outside of an action or component, but throwing a nice error message when using watch
or dispatch
would be really helpful.
I just now realised that it's all based on Proxy. As far as I know, babel can't polyfill Proxies.
This definitly isn't great. We are looking into how we can polyfill proxies for browsers that do not support it. This looks promising, yet still does not polyfill all traps we use.
We have an experiemental ESLint plugin that will error when using state outside of an action or component
I don't think that's enough: if your model is not in model.ts
, then it will fail even if used in an action.
So while an eslint plugin would be nice, I think a nice runtime error would be better.
Thinking more about it, watch
and dispatch
aren't enough because watch(state.foo)
will fail with can't read foo of undefined
because calling the function. So probably need a catch-all proxy that throws all the time.
Yes that's a good point. Relevant issue https://github.com/prodo-ai/prodo/issues/34.
@Onurbon asked me to have a look so here are a couple of thoughts:
## Installation
that I can copy paste in the readme 😄prodo
:const App = () => { //
setCount
would be `dispatch(model.action(state => x => { fnPassedToUseState(state) = x })) behind the scene const [count, setCount] = useState((state: State) => state.count)// in case
useState
isn't enough const action = useAction((state: State) => { // do whatever }) return ({count}
); }
export default App;