-
Notifications
You must be signed in to change notification settings - Fork 35
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
Update handlers API #68
Comments
I think that option 2 is my least favorite. You can get into situations where you have invalid state and there is no good work around for it. I see your point about keeping the API as small as possible. If that's the goal then option 1 seems the best. I have seen in a few libraries the type of pattern in option 3. Where the user has a base function that handles the normal case and a more powerful function for the not-so-normal cases. The state being available usually needed unless you have some async stuff going on where while you are updating a field and an async callback comes in with stale data which nukes the changes you just made. |
Oh I forgot one more option we discussed in PR that's prolly the best of both worlds. We can add optional flag to ppx: ["re-formality/ppx", "--target=react-dom"]
["re-formality/ppx", "--target=react-native"] And default it to Then API would be: // Defined in Formality
type updatePayload = {
value: string,
checked: bool,
};
// Application
<input onChange={form.updateEmail(({value}, input) => {...input, email: value})} /> |
Could that be at a per file level? We have a monorepo with both react native and web apps which would cause is to use this in one of the other but never both. |
What about environment variable |
We compile everything together so a flag like that would be about the same for us. Could we do something like:
|
Just checked, should be possible! We can use environment variable And local override: module X = [%form
{target: ReactNative};
type input = {a: string};
type output = {a: int};
]; PPX flag vs environment variable: I don't use ReactNative so question. Is it common case to have package with |
We do have some components that do cross over the web/native boundary. An environment variable with a local override sounds like a pretty nice flexible solution. |
@johnhaley81 And one more question: is there a pooling issue in react native? Usually, 2 things are useful from event target: But if in react-native input components expose strongly typed events, then to provide either |
Or maybe I can expose |
Looks like event is not required at all in react-native. |
My assumptions are based on:
But there are similar handlers that receive events, so I'm not sure. |
I.e. if only next value is required, then mentioned handlers can be used. But if developer uses event-based handler, then it means that there's something else needed from event and developer would be extracting stuff anyway, so it makes sense to keep |
Also, does it makes sense to change blur handler so it accepts event as well for consistency? <input
onBlur={form.blurEmail}
onChange={form.updateEmail((input, target) => {...input, email: target##value})}
/> |
Implemented in #72 |
We faced the case when implemented change didn't work. The current update handler expects that event is always of <input
onBlur={form.blurEmail}
onChange={
event =>
form.updateEmail(event->ReactEvent.toSyntheticEvent, (input, target) =>
{...input, email: target##value}
)
}
/> /cc @johnhaley81 |
I'm not sure that there can't be the case when there is no event provided at all. E.g. some custom component exposes just string. In this case, event capturing wouldn't work. |
Unfortunately, we should revert #72. https://ant.design/components/slider/ |
@alexfedoseev looking at how different components can be passing back values, I think assuming a specific type of value is coming back is probably a misstep. While putting I think reverting #72 is a good move unfortunately. Instead of assuming the type of value coming in, we could have the updater functions be in the form of: let updateField: ((`state, `field) => `state, `field) => unit; This would allow re-formality to be used anywhere for any component since we only care about getting the type of the field which is as small of a requirement as possible. Additionally, we could provide some utility functions that make getting values from DOM elements consistent. Something with functions like: let getValueFromEvent: ReactEvent.Form.t => string =
event => event->ReactEvent.Form.target##value;
let getCheckedFromEvent: ReactEvent.Form.t => bool =
event => event->ReactEvent.Form.target##checked; Which could be composed with the let (>>) = (g, f, a) => g(f(a)); What it looks like all together: <input
onChange={
getValueFromEvent >> form.updateEmail((form, email) => {...form, email})
}
/> And with components that don't directly give you access to the DOM it would be pretty simple. <DatePicker onChange=form.updateDate((form, date) => {...form, date}) /> |
@johnhaley81 Sorry for the delay, passing in value makes sense and it's done in #78. Can you review it, please? |
Currently, field update handler takes function of type
input => input
. Mainly, b/c it guarantees thatinput
value is not stale. But introduces unfortunate caveat:This runtime error happens due to React's
SyntheticEvent
being pooled. Since callback gets triggered asynchronously, by the time it gets called, the event is already null'ed by React.Options
Pros: guaranteed that
input
value is not stale.Cons: possible runtime error due to event pooling.
input
:Pros: No event pooling issue.
Cons: possibility of staled
input
.Pros: It's possible to choose a way to update input.
Cons: Bigger API surface and possibility to introduce both issues in user code.
The text was updated successfully, but these errors were encountered: