Skip to content

Instantly share code, notes, and snippets.

@v1vendi
Last active October 21, 2018 21:27
Show Gist options
  • Save v1vendi/e075500ff1e6be582378a3c425f79837 to your computer and use it in GitHub Desktop.
Save v1vendi/e075500ff1e6be582378a3c425f79837 to your computer and use it in GitHub Desktop.
React components for a page that does http request itself without redux
<title>Parcel demo</title>
<!-- <link rel=stylesheet href=./style.css /> -->
<style>
body {
max-width: 500px;
margin: auto;
}
#modal_holder:empty {
display: none;
}
#modal_holder:not(:empty) {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,.3);
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
#modal_holder .dialog {
background: white;
border: 1px solid #333;
padding: 2em;
}
li {
margin: 5px 0;
list-style-type: none;
}
button {
margin-left: 1em;
}
</style>
<h1>Some page</h1>
<main id=main></main>
<div id=modal_holder></div>
<script src=./index.js />
import '@babel/polyfill'
import React from 'react'
import ReactDOM from 'react-dom'
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
const SomeAPI = {
async fetch() {
await sleep(3000)
// throw <span>{'Error while fetching'}</span>
return [{
name: 'Item X',
id: 'x_id',
}, {
name: 'Item Y',
id: 'y_id',
}]
},
async post(id, param=null) {
await sleep(3000)
throw (
<span>
Error while posting for <b>{id}</b>
</span>
)
let message = `called post action for ${id}`
if (param) message += ` with param ${param}`
console.log(message)
}
}
class SomeComponent extends React.Component {
state = {
loading: false,
error: false,
data: [],
}
componentDidMount() {
this.load()
}
async load() {
this.setState({
loading: true,
})
try {
const data = await SomeAPI.fetch()
this.setState({
loading: false,
data,
})
} catch(error) {
this.setState({
loading: false,
error
})
}
}
renderItem(item) {
return (
<li key={item.id}>
{item.name}
<ActionButton {...item} />
</li>
)
}
render() {
if (this.state.loading) return 'Fetching data'
if (this.state.error) return this.state.error
return (
<ul>
{this.state.data.map(this.renderItem)}
</ul>
)
}
}
class ActionButton extends React.Component {
state = {
loading: false,
}
async handleClick() {
this.setState({
loading: true
})
try {
let result
// result = await ModalManager.render(ConfirmationModal, this.props) // ConfirmationModal, FormModal
await SomeAPI.post(this.props.id, result)
} catch (error) {
this.setState({
error,
})
// await ModalManager.render(ErrorModal, {
// message: reason
// })
} finally {
this.setState({
loading: false,
})
ModalManager.close()
}
}
render() {
let body = `Post for ${this.props.id}`
if (this.state.loading) body = `Posting for ${this.props.name}...`
if (this.state.error) body = this.state.error
return (
<button onClick={() => this.handleClick()} disabled={this.state.loading || this.state.error}>
{body}
</button>
)
}
}
class ConfirmationModal extends React.Component {
state = {
loading: false
}
submit() {
this.setState({
loading: true,
})
this.props.onSubmit()
}
decline() {
this.props.onDecline('You did not want to')
}
render() {
return (
<div>
<h1>Do some action with {this.props.name}?</h1>
<footer>
<button onClick={() => this.submit()}>
{this.state.loading ? 'Posting...' : 'Submit'}
</button>
<button onClick={() => this.decline()}>
Cancel
</button>
</footer>
</div>
)
}
}
class FormModal extends React.Component {
state = {
...ConfirmationModal.state,
value: '',
}
submit() {
this.setState({
loading: true,
})
this.props.onSubmit(this.state.value)
}
decline() {
this.props.onDecline('You did not want to')
}
render() {
return (
<div>
<h1>Do some action with {this.props.name}</h1>
<label>Set some param:</label>
&nbsp;
<input
value={this.state.value}
onChange={evt => this.setState({ value: evt.target.value })}
/>
<button onClick={() => this.submit()}>
{this.state.loading ? 'Posting...' : 'Submit'}
</button>
<button onClick={() => this.decline()}>
Cancel
</button>
</div>
)
}
}
class ErrorModal extends React.Component {
render() {
return (
<div>
<p>{this.props.message}</p>
<button onClick={this.props.onSubmit}>
Close
</button>
</div>
)
}
}
const ModalManager = {
render(Component, props) {
return new Promise((resolve, reject) => {
const modal = (
<div className='dialog'>
<Component
{...props}
onSubmit={resolve}
onDecline={reject}
/>
</div>
)
ReactDOM.render(modal, document.getElementById('modal_holder'))
})
},
close() {
ReactDOM.render(null, document.getElementById('modal_holder'))
}
}
ReactDOM.render(
<SomeComponent />,
document.getElementById('main')
)
{
"main": "index.html",
"scripts": {
"start": "parcel index.html"
},
"author": "i_komsa@wargaming.net",
"babel": {
"presets": [
"@babel/env",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-proposal-class-properties"
]
},
"browserslist": ["chrome 68"],
"dependencies": {
"@babel/cli": "^7.1.0",
"@babel/core": "^7.1.0",
"@babel/plugin-proposal-class-properties": "^7.1.0",
"@babel/polyfill": "^7.0.0",
"@babel/preset-env": "^7.1.0",
"@babel/preset-react": "^7.0.0",
"parcel-bundler": "^1.10.1",
"babel-plugin-async-to-promises": "^1.0.5",
"react": "^16.5.2",
"react-dom": "^16.5.2"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment