-
Notifications
You must be signed in to change notification settings - Fork 26.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Show both internal and shared state managment in example. #7312
Changes from 9 commits
837cb45
641e0e2
c34decf
9a83571
6326057
ca8fbfa
c250e97
03e7282
bf448b2
ea84168
2bd23b5
d9af316
8a277c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
module type Config = { | ||
type context; | ||
let defaultValue: context; | ||
}; | ||
|
||
module Make = (Config: Config) => { | ||
let x = React.createContext(Config.defaultValue); | ||
|
||
module Provider = { | ||
let make = x->React.Context.provider; | ||
|
||
[@bs.obj] | ||
external makeProps: | ||
( | ||
~value: Config.context, | ||
~children: React.element, | ||
~key: string=?, | ||
unit | ||
) => | ||
{ | ||
. | ||
"value": Config.context, | ||
"children": React.element, | ||
} = | ||
""; | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
type reducer = (CountContext.state, CountContext.action => unit); | ||
|
||
[@react.component] | ||
let make = () => { | ||
let ({count}, dispatch): reducer = React.useContext(CountContext.x); | ||
|
||
<div> | ||
<div> {j|This is the count: $count|j}->React.string </div> | ||
<button onClick={_e => dispatch(CountContext.Increment)}> | ||
"Increment count"->React.string | ||
</button> | ||
</div>; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
type state = {count: int}; | ||
type action = | ||
| Increment; | ||
let init = {count: 0}; | ||
let reducer = (state, action) => { | ||
switch (action) { | ||
| Increment => {count: state.count + 1} | ||
}; | ||
}; | ||
|
||
type t = (state, action => unit); | ||
|
||
include Context.Make({ | ||
type context = t; | ||
let defaultValue = ( | ||
init, | ||
_ => { | ||
(); | ||
}, | ||
); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[@react.component] | ||
let make = (~children) => { | ||
let reducer = React.useReducer(CountContext.reducer, CountContext.init); | ||
|
||
<CountContext.Provider value=reducer> children </CountContext.Provider>; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
## Global Count | ||
This captures the count globally so that it will be persisted across | ||
the `Index` and `About` pages. This replicates the functionality | ||
of the shared-modules example. | ||
*/ | ||
type t = ref(int); | ||
|
||
type action = | ||
| Increment; | ||
|
||
let current = ref(0); | ||
|
||
let increment = () => { | ||
current := current^ + 1; | ||
current; | ||
}; | ||
|
||
let reducer = (_state, action) => { | ||
switch(action) { | ||
| Increment => | ||
let updated = increment(); | ||
updated^ | ||
} | ||
}; | ||
|
||
let useGlobalCount = () => React.useReducer(reducer, current^); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import App, { Container } from 'next/app' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was the file I was trying to avoid adding. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you play around with next for any considerable amount of time you will probably use this file at some point. I don't see a reason to avoid it when it's provided to allow you to do this very thing. |
||
import React from 'react' | ||
import { make as CountProvider } from '../components/CountProvider.bs' | ||
|
||
class MyApp extends App { | ||
static async getInitialProps({ Component, router, ctx }) { | ||
let pageProps = {} | ||
|
||
if (Component.getInitialProps) { | ||
pageProps = await Component.getInitialProps(ctx) | ||
} | ||
|
||
return { pageProps } | ||
} | ||
|
||
render() { | ||
const { Component, pageProps, store } = this.props | ||
return ( | ||
<Container> | ||
<CountProvider> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel like this wrapping is exactly what the Hooks API is trying to avoid. Is there another way we can inject the provider? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, we're injecting context in a place where it takes quite a leap to find. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think there is another way to inject the provider if we want it to work on every page without having to prepend it to the top level of As far as wrapping and how it relates to hooks, you still need a Provider, so I don't think there is a way to get around wrapping in terms of the context API. Maybe in the new version of reductive this will be solved. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like a lot of ceremony to avoid the use of a Also, now we are introducing many more concepts, steps and indirections. I get that you may have to use this file eventually, but is it necessary in this case? Should it be something that should be avoided unless really necessary? To me, it’s akin to using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is definitely more boilerplate here and I don't really like that at all. At the same time, you can make the same comments about |
||
<Component {...pageProps} /> | ||
</CountProvider> | ||
</Container> | ||
) | ||
} | ||
} | ||
|
||
export default MyApp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this file mean? It was quite difficult to explain this to a non-react user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was the example I found in the discord channel. As far as what it means, it would probably require some discussion on functors in Ocaml/ReasonML but I would argue this file is not as important as
CountContext.re
which provides the API for how to create a global value using the context API. I could always add comments to this file that explains things more.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I agree that it will take some discussion of Functors, and module composition (because of the
include
). Also, this requires a lot of knowledge of React internals.I think this is rather scary for someone new. I like this example because it does showcase some more advanced functionality. But perhaps it should be it’s own example? Removing the
ref
fromwith-reasonml
and making the context example beingwith-reasonml-context
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is fine having it in a separate example. I am not that attached like I said before. It's was definitely interesting exploring the context API and how to implement it here.