make UI snappy
This commit is contained in:
parent
5a0a7e495c
commit
c236cc7ac6
1 changed files with 86 additions and 15 deletions
83
src/App.js
83
src/App.js
|
|
@ -20,16 +20,34 @@ class App extends Component {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
logState = () => {
|
||||||
|
console.log(this.state)
|
||||||
|
}
|
||||||
saveTodo = (e) => {
|
saveTodo = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
const { todos } = this.state
|
||||||
|
const todoValue = this.inputElement.value
|
||||||
|
|
||||||
if (!this.inputElement.value) {
|
if (!todoValue) {
|
||||||
alert('Please add todo text')
|
alert('Please add todo text')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Optimistically add todo to UI
|
||||||
|
const temporaryValue = {
|
||||||
|
data: {
|
||||||
|
title: todoValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const optimisticTodoState = todos.concat(temporaryValue)
|
||||||
|
this.setState({
|
||||||
|
todos: optimisticTodoState
|
||||||
|
})
|
||||||
|
|
||||||
|
// Make API request to create new todo
|
||||||
fetch('/.netlify/functions/todos-create', {
|
fetch('/.netlify/functions/todos-create', {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
title: this.inputElement.value
|
title: todoValue
|
||||||
}),
|
}),
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
// mode: 'cors', // no-cors, cors, *same-origin
|
// mode: 'cors', // no-cors, cors, *same-origin
|
||||||
|
|
@ -37,13 +55,46 @@ class App extends Component {
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
console.log(json)
|
console.log(json)
|
||||||
|
// remove temporaryValue from state and persist API response
|
||||||
|
const persistedState = removeOptimisticTodo(todos).concat(json)
|
||||||
|
// Set persisted value to state
|
||||||
|
this.setState({
|
||||||
|
todos: persistedState
|
||||||
|
})
|
||||||
|
// fin
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
console.log('errrrr', e)
|
console.log('An API error occurred', e)
|
||||||
|
const revertedState = removeOptimisticTodo(todos)
|
||||||
|
// Reset to original state
|
||||||
|
this.setState({
|
||||||
|
todos: revertedState
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
deleteTodo = (e) => {
|
deleteTodo = (e) => {
|
||||||
|
const { todos } = this.state
|
||||||
const todoId = e.target.dataset.id
|
const todoId = e.target.dataset.id
|
||||||
console.log(`Delete todo ${todoId}`)
|
console.log(`Delete todo ${todoId}`)
|
||||||
|
// Optimistically remove todo from UI
|
||||||
|
const filteredTodos = todos.reduce((acc, current) => {
|
||||||
|
const currentId = getTodoId(current)
|
||||||
|
if (currentId === todoId) {
|
||||||
|
// save item being removed for rollback
|
||||||
|
acc.rollbackTodo = current
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
// filter deleted todo out of the todos list
|
||||||
|
acc.optimisticState = acc.optimisticState.concat(current)
|
||||||
|
return acc
|
||||||
|
}, {
|
||||||
|
rollbackTodo: {},
|
||||||
|
optimisticState: []
|
||||||
|
})
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
todos: filteredTodos.optimisticState
|
||||||
|
})
|
||||||
|
// Make API request to delete todo
|
||||||
fetch(`/.netlify/functions/todos-delete/${todoId}`, {
|
fetch(`/.netlify/functions/todos-delete/${todoId}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
})
|
})
|
||||||
|
|
@ -51,14 +102,19 @@ class App extends Component {
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
console.log(json)
|
console.log(json)
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
console.log('errrrr', e)
|
console.log(`There was an error removing ${todoId}`, e)
|
||||||
|
// Add item removed back to list
|
||||||
|
this.setState({
|
||||||
|
todos: filteredTodos.optimisticState.concat(filteredTodos.rollbackTodo)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
renderTodos() {
|
renderTodos() {
|
||||||
const { todos } = this.state
|
const { todos } = this.state
|
||||||
return todos.map((todo, i) => {
|
return todos.map((todo, i) => {
|
||||||
const { data } = todo
|
const { data, ref } = todo
|
||||||
const id = todo.ref['@ref'].split('/').pop()
|
const id = getTodoId(todo)
|
||||||
|
console.log('id', id)
|
||||||
return (
|
return (
|
||||||
<div key={i} style={{borderBottom: '1px solid black', padding: 20}}>
|
<div key={i} style={{borderBottom: '1px solid black', padding: 20}}>
|
||||||
{data.title} <button data-id={id} onClick={this.deleteTodo}>delete</button>
|
{data.title} <button data-id={id} onClick={this.deleteTodo}>delete</button>
|
||||||
|
|
@ -77,6 +133,7 @@ class App extends Component {
|
||||||
Using FaunaDB & netlify functions
|
Using FaunaDB & netlify functions
|
||||||
</p>
|
</p>
|
||||||
<div>
|
<div>
|
||||||
|
<button onClick={this.logState}>log state</button>
|
||||||
<h2>Create todo</h2>
|
<h2>Create todo</h2>
|
||||||
<form className='feature-add' onSubmit={this.saveTodo}>
|
<form className='feature-add' onSubmit={this.saveTodo}>
|
||||||
<input placeholder='Todo Info' name='name' ref={el => this.inputElement = el} />
|
<input placeholder='Todo Info' name='name' ref={el => this.inputElement = el} />
|
||||||
|
|
@ -92,4 +149,18 @@ class App extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeOptimisticTodo(todos) {
|
||||||
|
// return all 'real' todos
|
||||||
|
return todos.filter((todo) => {
|
||||||
|
return todo.ref
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTodoId(todo) {
|
||||||
|
if (!todo.ref) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return todo.ref['@ref'].split('/').pop()
|
||||||
|
}
|
||||||
|
|
||||||
export default App
|
export default App
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue