Conversation
|
Hey @dotcypress - good call on this. Just so I have a better grasp in my head, what's your best "here's why this is awesome" use-case for the callback?
|
src/index.js
Outdated
| * @returns {function} linkedStateHandler | ||
| */ | ||
| export default function linkState(component, key, eventPath) { | ||
| export default function linkState(component, key, eventPath, cb) { |
There was a problem hiding this comment.
Only suggestion I'd make would be to use the full word callback here. It gets minified out anyway, and it's just that little bit more understandable for newcomers! 😊
|
Hey @developit import linkState from 'linkstate'
const noop = () => {}
export default function linkedForm (component, rules, opts = {}) {
let pristine = true
function createPatch (errors = {}) {
return { [opts.errorsPath || 'errors']: errors }
}
function validate () {
pristine = false
const errors = Object.keys(rules).reduce((acc, statePath) => {
const validator = rules[statePath] || noop
const error = validator(component.state)
if (error) {
acc[statePath] = error
}
return acc
}, {})
component.setState(createPatch(errors))
return Object.keys(errors).length === 0
}
Object.assign(component.state, createPatch())
return {
validate,
linkState: (statePath, valuePath) =>
linkState(component, statePath, valuePath, () => !pristine && validate()),
reset: () => {
pristine = true
component.setState(createPatch())
}
}
}Example component: class SignupPage extends Component {
constructor (props) {
super(props)
this.state = {
email: '',
password: '',
firstName: '',
lastName: ''
}
this.form = linkedForm(this, {
firstName: ({ firstName, mode }) => !firstName && 'Please enter a valid name.',
lastName: ({ lastName, mode }) => !lastName && 'Please enter a valid name.',
email: ({ email }) => !isEmail(email) && 'Please enter correct email',
password: ({ password }) => password.length < 5 && 'Password must contain at least 5 characters.'
})
}
handleSubmit () {
const { email, password, firstName, lastName } = this.state
if (!this.form.validate()) {
return
}
signup(email, firstName, lastName, password).then(() => this.form.reset())
}
render () {
const { errors, email, password, firstName, lastName } = this.state
return (
<form onSubmit={this.handleSubmit}>
<input type='text' value={firstName} onChange={this.form.linkState('firstName')}/>
{errors.firstName && <strong>{errors.firstName}</strong>}
<input type='text' value={lastName} onChange={this.form.linkState('lastName')}/>
{errors.lastName && <strong>{errors.lastName}</strong>}
<input type='email' value={email} onChange={this.form.linkState('email')}/>
{errors.email && <strong>{errors.email}</strong>}
<input type='password' value={password} onChange={this.form.linkState('password')}/>
{errors.password && <strong>{errors.password}</strong>}
<button type='submit'>Register</button>
</form>
)
}
}As you see, we need to revalidate form in some cases, but we use current component state as input. So, we need to wait for state settle. Of course, i can validate input before placing it to state, and validation result will be saved to state. But in this situation, validation changes renders before actual state changes, and this behavior is questionable. UPD: And, well, if i will validate before calling |
|
Nice - I'm seeing hints in there that you've done Angular haha. Question though - in the above example, could validation have been done in |
|
Angular? It was long time ago 😆 Yes, |
|
Kindly reminder on this. |
|
Yup, sorry for dropping this on the floor. Still need to contact a few people about this to make sure we're good to change the API. |
|
+1 for this |
Add callback argument to build some cool stuff around
linkstate👌We use our bike-shed for form validation, but our implementation of
linkStateis so naive and we really want to use this great module as dependency. 👍