First adoption of React hooks (#3096)
I did this as a warm-up to using [React hooks](https://reactjs.org/docs/hooks-intro.html), which provide a better way to accomplish stateful things and side effects using functional components. This allows all components to be written in the same style, improves testability, facilitates code reuse, etc. There's [a intro here](https://reactjs.org/docs/hooks-intro.html) which links to [Dan's talk at React Conf](https://www.youtube.com/watch?time_continue=3599&v=dpw9EHDh2bM) which does a really good job of explaining why hooks are a good way to write components. He describes hooks as being the electrons and neutrons to components which are atoms. Low-level functionality which was always there in React, though not as accessibly or visibly. This adds a lint rule that enforces "the rule of hooks" which says they have to be declared at the top level in the functional component. I don't think this changeset does a fabulous job of showing off the improvements hooks allows, though I think it is still a good direction for this code.
This commit is contained in:
@@ -5,12 +5,12 @@ const Donate = styled.div`
|
||||
padding: 25px 50px;
|
||||
`
|
||||
|
||||
const DonateBox = () => (
|
||||
<Donate>
|
||||
Love Shields? Please consider{' '}
|
||||
<a href="https://opencollective.com/shields">donating</a> to sustain our
|
||||
activities
|
||||
</Donate>
|
||||
)
|
||||
|
||||
export default DonateBox
|
||||
export default function DonateBox() {
|
||||
return (
|
||||
<Donate>
|
||||
Love Shields? Please consider{' '}
|
||||
<a href="https://opencollective.com/shields">donating</a> to sustain our
|
||||
activities
|
||||
</Donate>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import React from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { dynamicBadgeUrl } from '../../core/badge-urls/make-badge-url'
|
||||
import { InlineInput } from './common'
|
||||
|
||||
export default class DynamicBadgeMaker extends React.Component {
|
||||
static propTypes = {
|
||||
baseUrl: PropTypes.string,
|
||||
}
|
||||
|
||||
state = {
|
||||
function DynamicBadgeMaker({ baseUrl = document.location.href }) {
|
||||
const [values, setValues] = useState({
|
||||
datatype: '',
|
||||
label: '',
|
||||
dataUrl: '',
|
||||
@@ -16,21 +12,25 @@ export default class DynamicBadgeMaker extends React.Component {
|
||||
color: '',
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
})
|
||||
|
||||
const isValid = ['datatype', 'label', 'dataUrl', 'query'].every(
|
||||
k => values[k]
|
||||
)
|
||||
|
||||
const onChange = ({ target: { name, value } }) => {
|
||||
setValues({
|
||||
...values,
|
||||
[name]: value,
|
||||
})
|
||||
}
|
||||
|
||||
makeBadgeUrl() {
|
||||
const {
|
||||
datatype,
|
||||
label,
|
||||
dataUrl,
|
||||
query,
|
||||
color,
|
||||
prefix,
|
||||
suffix,
|
||||
} = this.state
|
||||
const { baseUrl: baseUrl = document.location.href } = this.props
|
||||
return dynamicBadgeUrl({
|
||||
baseUrl: baseUrl || window.location.href,
|
||||
const onSubmit = e => {
|
||||
e.preventDefault()
|
||||
|
||||
const { datatype, label, dataUrl, query, color, prefix, suffix } = values
|
||||
document.location = dynamicBadgeUrl({
|
||||
baseUrl,
|
||||
datatype,
|
||||
label,
|
||||
dataUrl,
|
||||
@@ -41,69 +41,38 @@ export default class DynamicBadgeMaker extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault()
|
||||
document.location = this.makeBadgeUrl()
|
||||
}
|
||||
const inputs = [
|
||||
{ name: 'label' },
|
||||
{ name: 'dataUrl', placeholder: 'data url' },
|
||||
{ name: 'query' },
|
||||
{ name: 'color' },
|
||||
{ name: 'prefix' },
|
||||
{ name: 'suffix' },
|
||||
]
|
||||
|
||||
get isValid() {
|
||||
const { datatype, label, dataUrl, query } = this.state
|
||||
return datatype && label && dataUrl && query
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<form onSubmit={e => this.handleSubmit(e)}>
|
||||
<select
|
||||
className="short"
|
||||
onChange={event => this.setState({ datatype: event.target.value })}
|
||||
value={this.state.datatype}
|
||||
>
|
||||
<option disabled value="">
|
||||
data type
|
||||
</option>
|
||||
<option value="json">json</option>
|
||||
<option value="xml">xml</option>
|
||||
<option value="yaml">yaml</option>
|
||||
</select>{' '}
|
||||
return (
|
||||
<form onSubmit={onSubmit}>
|
||||
<select name="datatype" onChange={onChange} value={values.datatype}>
|
||||
<option disabled value="">
|
||||
data type
|
||||
</option>
|
||||
<option value="json">json</option>
|
||||
<option value="xml">xml</option>
|
||||
<option value="yaml">yaml</option>
|
||||
</select>{' '}
|
||||
{inputs.map(({ name, placeholder = name }) => (
|
||||
<InlineInput
|
||||
className="short"
|
||||
onChange={event => this.setState({ label: event.target.value })}
|
||||
placeholder="label"
|
||||
value={this.state.label}
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
placeholder={placeholder}
|
||||
value={values[name]}
|
||||
/>
|
||||
<InlineInput
|
||||
className="short"
|
||||
onChange={event => this.setState({ dataUrl: event.target.value })}
|
||||
placeholder="data url"
|
||||
value={this.state.dataUrl}
|
||||
/>
|
||||
<InlineInput
|
||||
className="short"
|
||||
onChange={event => this.setState({ query: event.target.value })}
|
||||
placeholder="query"
|
||||
value={this.state.query}
|
||||
/>
|
||||
<InlineInput
|
||||
className="short"
|
||||
onChange={event => this.setState({ color: event.target.value })}
|
||||
placeholder="color"
|
||||
value={this.state.color}
|
||||
/>
|
||||
<InlineInput
|
||||
className="short"
|
||||
onChange={event => this.setState({ prefix: event.target.value })}
|
||||
placeholder="prefix"
|
||||
value={this.state.prefix}
|
||||
/>
|
||||
<InlineInput
|
||||
className="short"
|
||||
onChange={event => this.setState({ suffix: event.target.value })}
|
||||
placeholder="suffix"
|
||||
value={this.state.suffix}
|
||||
/>
|
||||
<button disabled={!this.isValid}>Make Badge</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
))}
|
||||
<button disabled={!isValid}>Make Badge</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
export default DynamicBadgeMaker
|
||||
DynamicBadgeMaker.propTypes = {
|
||||
baseUrl: PropTypes.string,
|
||||
}
|
||||
|
||||
@@ -1,65 +1,67 @@
|
||||
import React from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { staticBadgeUrl } from '../../core/badge-urls/make-badge-url'
|
||||
import { InlineInput } from './common'
|
||||
|
||||
export default class StaticBadgeMaker extends React.Component {
|
||||
static propTypes = {
|
||||
baseUrl: PropTypes.string,
|
||||
}
|
||||
|
||||
state = {
|
||||
function StaticBadgeMaker({ baseUrl = document.location.href }) {
|
||||
const [values, setValues] = useState({
|
||||
label: '',
|
||||
message: '',
|
||||
color: '',
|
||||
})
|
||||
|
||||
const isValid = ['message', 'color'].every(k => values[k])
|
||||
|
||||
const onChange = ({ target: { name, value } }) => {
|
||||
setValues({
|
||||
...values,
|
||||
[name]: value,
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit(e) {
|
||||
const onSubmit = e => {
|
||||
e.preventDefault()
|
||||
|
||||
const { baseUrl } = this.props
|
||||
const { label, message, color } = this.state
|
||||
const badgeUrl = staticBadgeUrl({
|
||||
baseUrl: baseUrl || window.location.href,
|
||||
label,
|
||||
message,
|
||||
color,
|
||||
})
|
||||
|
||||
document.location = badgeUrl
|
||||
const { label, message, color } = values
|
||||
document.location = staticBadgeUrl({ baseUrl, label, message, color })
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<form onSubmit={e => this.handleSubmit(e)}>
|
||||
<InlineInput
|
||||
onChange={event => this.setState({ label: event.target.value })}
|
||||
placeholder="label"
|
||||
value={this.state.label}
|
||||
/>
|
||||
<InlineInput
|
||||
onChange={event => this.setState({ message: event.target.value })}
|
||||
placeholder="message"
|
||||
value={this.state.message}
|
||||
/>
|
||||
<InlineInput
|
||||
list="default-colors"
|
||||
onChange={event => this.setState({ color: event.target.value })}
|
||||
placeholder="color"
|
||||
value={this.state.color}
|
||||
/>
|
||||
<datalist id="default-colors">
|
||||
<option value="brightgreen" />
|
||||
<option value="green" />
|
||||
<option value="yellowgreen" />
|
||||
<option value="yellow" />
|
||||
<option value="orange" />
|
||||
<option value="red" />
|
||||
<option value="lightgrey" />
|
||||
<option value="blue" />
|
||||
</datalist>
|
||||
<button>Make Badge</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<form onSubmit={onSubmit}>
|
||||
<InlineInput
|
||||
name="label"
|
||||
onChange={onChange}
|
||||
placeholder="label"
|
||||
value={values.label}
|
||||
/>
|
||||
<InlineInput
|
||||
name="message"
|
||||
onChange={onChange}
|
||||
placeholder="message"
|
||||
value={values.message}
|
||||
/>
|
||||
<InlineInput
|
||||
list="default-colors"
|
||||
name="color"
|
||||
onChange={onChange}
|
||||
placeholder="color"
|
||||
value={values.color}
|
||||
/>
|
||||
<datalist id="default-colors">
|
||||
<option value="brightgreen" />
|
||||
<option value="green" />
|
||||
<option value="yellowgreen" />
|
||||
<option value="yellow" />
|
||||
<option value="orange" />
|
||||
<option value="red" />
|
||||
<option value="lightgrey" />
|
||||
<option value="blue" />
|
||||
</datalist>
|
||||
<button disabled={!isValid}>Make Badge</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
export default StaticBadgeMaker
|
||||
StaticBadgeMaker.propTypes = {
|
||||
baseUrl: PropTypes.string,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user