Skip to content

Instantly share code, notes, and snippets.

@webuniverseio
Last active December 5, 2021 19:20
Show Gist options
  • Save webuniverseio/3404381b5b9b6d99c3d74b9a5cc6c075 to your computer and use it in GitHub Desktop.
Save webuniverseio/3404381b5b9b6d99c3d74b9a5cc6c075 to your computer and use it in GitHub Desktop.
reading order
// https://epicreact.dev/why-you-shouldnt-put-refs-in-a-dependency-array/
import * as React from 'react'
import * as ReactDOM from 'react-dom'
function UsernameForm({
initialUsername = '',
onSubmitUsername,
}) {
const [username, setUsername] = React.useState(initialUsername)
const [touched, setTouched] = React.useState(false)
const usernameInputRef = React.useRef(null)
const usernameIsLowerCase = username === username.toLowerCase()
const usernameIsLongEnough = username.length >= 3
const usernameIsShortEnough = username.length <= 10
const formIsValid =
usernameIsShortEnough && usernameIsLongEnough && usernameIsLowerCase
const displayErrorMessage = touched && !formIsValid
React.useEffect(() => {
if (displayErrorMessage) usernameInputRef.current?.focus()
}, [displayErrorMessage])
let errorMessage = null
if (!usernameIsLowerCase) {
errorMessage = 'Username must be lower case'
} else if (!usernameIsLongEnough) {
errorMessage = 'Username must be at least 3 characters long'
} else if (!usernameIsShortEnough) {
errorMessage = 'Username must be no longer than 10 characters'
}
function handleSubmit(event) {
event.preventDefault()
setTouched(true)
if (!formIsValid) return
onSubmitUsername(username)
}
function handleChange(event) {
setUsername(event.currentTarget.value)
}
function handleBlur() {
setTouched(true)
}
return (
<form name="usernameForm" onSubmit={handleSubmit} noValidate>
<div>
<label htmlFor="usernameInput">Username:</label>
<input
ref={usernameInputRef}
id="usernameInput"
type="text"
value={username}
onChange={handleChange}
onBlur={handleBlur}
pattern="[a-z]{3,10}"
required
aria-describedby={displayErrorMessage ? 'error-message' : undefined}
/>
</div>
{displayErrorMessage ? (
<div role="alert" className="error-message">
{errorMessage}
</div>
) : null}
<button type="submit">Submit</button>
</form>
)
}
ReactDOM.render(<UsernameForm />, document.querySelector('#root'), () => {
const input = document.querySelector('#usernameInput')
input.focus()
input.blur()
timeout()
.then(() => {
console.log(document.querySelector('.error-message')?.textContent)
document.querySelector('button').click()
})
.then(() => {
console.log(document.querySelector('.error-message')?.textContent)
})
})
function timeout() {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, 0);
})
}
// https://epicreact.dev/why-you-shouldnt-put-refs-in-a-dependency-array/
import * as React from 'react'
import * as ReactDOM from 'react-dom'
function UsernameForm({
initialUsername = '',
onSubmitUsername,
}) {
// region setup
const [username, setUsername] = React.useState(initialUsername)
const [touched, setTouched] = React.useState(false)
const usernameInputRef = React.useRef(null)
// endregion
// region user state
const usernameIsLowerCase = username === username.toLowerCase()
const usernameIsLongEnough = username.length >= 3
const usernameIsShortEnough = username.length <= 10
const formIsValid =
usernameIsShortEnough && usernameIsLongEnough && usernameIsLowerCase
// endregion
// region effects
const displayErrorMessage = touched && !formIsValid
React.useEffect(() => {
if (displayErrorMessage) usernameInputRef.current?.focus()
}, [displayErrorMessage])
// endregion
// region error message state
let errorMessage = null
if (!usernameIsLowerCase) {
errorMessage = 'Username must be lower case'
} else if (!usernameIsLongEnough) {
errorMessage = 'Username must be at least 3 characters long'
} else if (!usernameIsShortEnough) {
errorMessage = 'Username must be no longer than 10 characters'
}
// endregion
// region handlers
function handleSubmit(event) {
event.preventDefault()
setTouched(true)
if (!formIsValid) return
onSubmitUsername(username)
}
function handleChange(event) {
setUsername(event.currentTarget.value)
}
function handleBlur() {
setTouched(true)
}
// endregion
return (
<form name="usernameForm" onSubmit={handleSubmit} noValidate>
<div>
<label htmlFor="usernameInput">Username:</label>
<input
ref={usernameInputRef}
id="usernameInput"
type="text"
value={username}
onChange={handleChange}
onBlur={handleBlur}
pattern="[a-z]{3,10}"
required
aria-describedby={displayErrorMessage ? 'error-message' : undefined}
/>
</div>
{displayErrorMessage ? (
<div role="alert" className="error-message">
{errorMessage}
</div>
) : null}
<button type="submit">Submit</button>
</form>
)
}
ReactDOM.render(<UsernameForm />, document.querySelector('#root'), () => {
const input = document.querySelector('#usernameInput')
input.focus()
input.blur()
timeout()
.then(() => {
console.log(document.querySelector('.error-message')?.textContent)
document.querySelector('button').click()
})
.then(() => {
console.log(document.querySelector('.error-message')?.textContent)
})
})
function timeout() {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, 0);
})
}
// https://epicreact.dev/why-you-shouldnt-put-refs-in-a-dependency-array/
import * as React from 'react'
import * as ReactDOM from 'react-dom'
class UsernameForm extends React.Component {
constructor(props) {
super(props)
this.state = {
touched: false,
...this.getDerivedUserState(this.props.initialUsername || '')
}
this.usernameInputRef = React.createRef();
}
getDerivedUserState(username) {
const usernameIsLowerCase = username === username.toLowerCase()
const usernameIsLongEnough = username.length >= 3
const usernameIsShortEnough = username.length <= 10
const formIsValid =
usernameIsShortEnough && usernameIsLongEnough && usernameIsLowerCase
return {
username,
usernameIsShortEnough,
usernameIsLongEnough,
usernameIsLowerCase,
formIsValid
}
}
shouldDisplayErrorMessage() {
const {touched, formIsValid} = this.state
return touched && !formIsValid
}
componentDidUpdate() {
if (this.shouldDisplayErrorMessage()) {
this.usernameInputRef.current.focus()
}
}
getErrorMessage() {
const {usernameIsLowerCase, usernameIsLongEnough, usernameIsShortEnough} = this.state
if (!usernameIsLowerCase) {
return 'Username must be lower case'
} else if (!usernameIsLongEnough) {
return 'Username must be at least 3 characters long'
} else if (!usernameIsShortEnough) {
return 'Username must be no longer than 10 characters'
}
return null
}
handleBlur() {
this.setState({touched: true})
}
handleChange(event) {
this.setState(
this.getDerivedUserState(
event.currentTarget.value
)
)
}
handleSubmit(event) {
event.preventDefault()
const {formIsValid, username} = this.state
this.setState({touched: true})
if (!formIsValid) return
this.props.onSubmitUsername(username)
}
render() {
const {username} = this.state
const displayErrorMessage = this.shouldDisplayErrorMessage()
return (
<form name="usernameForm" onSubmit={e => this.handleSubmit(e)} noValidate>
<div>
<label htmlFor="usernameInput">Username:</label>
<input
ref={this.usernameInputRef}
id="usernameInput"
type="text"
value={username}
onChange={e => this.handleChange(e)}
onBlur={() => this.handleBlur()}
pattern="[a-z]{3,10}"
required
aria-describedby={displayErrorMessage ? 'error-message' : undefined}
/>
</div>
{displayErrorMessage ? (
<div role="alert" className="error-message">
{this.getErrorMessage()}
</div>
) : null}
<button type="submit">Submit</button>
</form>
)
}
}
ReactDOM.render(<UsernameForm />, document.querySelector('#root'), () => {
const input = document.querySelector('#usernameInput')
input.focus()
input.blur()
timeout()
.then(() => {
console.log(document.querySelector('.error-message')?.textContent)
document.querySelector('button').click()
})
.then(() => {
console.log(document.querySelector('.error-message')?.textContent)
})
})
function timeout() {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, 0);
})
}
// https://epicreact.dev/why-you-shouldnt-put-refs-in-a-dependency-array/
import * as React from 'react'
import * as ReactDOM from 'react-dom'
class UsernameForm extends React.Component {
constructor(props) {
super(props)
this.state = {
touched: false,
...this.getDerivedUserState(this.props.initialUsername || '')
}
this.usernameInputRef = React.createRef();
}
render() {
const {username} = this.state
const displayErrorMessage = this.shouldDisplayErrorMessage()
return (
<form name="usernameForm" onSubmit={e => this.handleSubmit(e)} noValidate>
<div>
<label htmlFor="usernameInput">Username:</label>
<input
ref={this.usernameInputRef}
id="usernameInput"
type="text"
value={username}
onBlur={() => this.handleBlur()}
onChange={e => this.handleChange(e)}
pattern="[a-z]{3,10}"
required
aria-describedby={displayErrorMessage ? 'error-message' : undefined}
/>
</div>
{displayErrorMessage ? (
<div role="alert" className="error-message">
{this.getErrorMessage()}
</div>
) : null}
<button type="submit">Submit</button>
</form>
)
}
shouldDisplayErrorMessage() {
const {touched, formIsValid} = this.state
return touched && !formIsValid
}
handleSubmit(event) {
event.preventDefault()
const {formIsValid, username} = this.state
this.setState({touched: true})
if (!formIsValid) return
this.props.onSubmitUsername(username)
}
handleBlur() {
this.setState({touched: true})
}
handleChange(event) {
this.setState(
this.getDerivedUserState(
event.currentTarget.value
)
)
}
getDerivedUserState(username) {
const usernameIsLowerCase = username === username.toLowerCase()
const usernameIsLongEnough = username.length >= 3
const usernameIsShortEnough = username.length <= 10
const formIsValid =
usernameIsShortEnough && usernameIsLongEnough && usernameIsLowerCase
return {
username,
usernameIsShortEnough,
usernameIsLongEnough,
usernameIsLowerCase,
formIsValid
}
}
getErrorMessage() {
const {usernameIsLowerCase, usernameIsLongEnough, usernameIsShortEnough} = this.state
if (!usernameIsLowerCase) {
return 'Username must be lower case'
} else if (!usernameIsLongEnough) {
return 'Username must be at least 3 characters long'
} else if (!usernameIsShortEnough) {
return 'Username must be no longer than 10 characters'
}
return null
}
componentDidUpdate() {
if (this.shouldDisplayErrorMessage()) {
this.usernameInputRef.current.focus()
}
}
}
ReactDOM.render(<UsernameForm />, document.querySelector('#root'), () => {
const input = document.querySelector('#usernameInput')
input.focus()
input.blur()
timeout()
.then(() => {
console.log(document.querySelector('.error-message')?.textContent)
document.querySelector('button').click()
})
.then(() => {
console.log(document.querySelector('.error-message')?.textContent)
})
})
function timeout() {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, 0);
})
}
import * as React from 'react'
import * as ReactDOM from 'react-dom'
function UsernameForm({
initialUsername = '',
onSubmitUsername,
}) {
const usernameInputRef = React.useRef(null)
function render() {
return (
<form name="usernameForm" onSubmit={handleSubmit} noValidate>
<div>
<label htmlFor="usernameInput">Username:</label>
<input
ref={usernameInputRef}
id="usernameInput"
type="text"
value={username}
onBlur={handleBlur}
onChange={handleChange}
pattern="[a-z]{3,10}"
required
aria-describedby={displayErrorMessage ? 'error-message' : undefined}
/>
</div>
{displayErrorMessage ? (
<div role="alert" className="error-message">
{errorMessage}
</div>
) : null}
<button type="submit">Submit</button>
</form>
)
}
function handleSubmit(event) {
event.preventDefault()
setTouched(true)
if (!isFormValid()) return
onSubmitUsername(username)
}
function handleBlur() {
setTouched(true)
}
function handleChange(event) {
setUsername(event.currentTarget.value)
}
function isFormValid() {
return usernameIsShortEnough && usernameIsLongEnough && usernameIsLowerCase
}
const [touched, setTouched] = React.useState(false)
const [username, setUsername] = React.useState(initialUsername)
const usernameIsLowerCase = username === username.toLowerCase()
const usernameIsLongEnough = username.length >= 3
const usernameIsShortEnough = username.length <= 10
const displayErrorMessage = touched && !isFormValid()
let errorMessage = null
if (!usernameIsLowerCase) {
errorMessage = 'Username must be lower case'
} else if (!usernameIsLongEnough) {
errorMessage = 'Username must be at least 3 characters long'
} else if (!usernameIsShortEnough) {
errorMessage = 'Username must be no longer than 10 characters'
}
React.useEffect(() => {
if (displayErrorMessage) usernameInputRef.current?.focus()
}, [displayErrorMessage])
return render()
}
ReactDOM.render(<UsernameForm />, document.querySelector('#root'), () => {
const input = document.querySelector('#usernameInput')
input.focus()
input.blur()
timeout()
.then(() => {
console.log(document.querySelector('.error-message')?.textContent)
document.querySelector('button').click()
})
.then(() => {
console.log(document.querySelector('.error-message')?.textContent)
})
})
function timeout() {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, 0);
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment