Reputation: 1136
I have a react app that fetches a list of todos from the backend, displays them in a list, and offers you a button to add a new one.
I notice that the newly added to do will only appear in the list AFTER I refresh the page (e.g. after it fetches from the backend). I'd like to force the component to re-render with the newly added to do, ideally without a backend call. How can I do that?
Component AFTER I've hit "add" - text stays in the box, does not appear in the list
Page AFTER I've hit add and refreshed the page - appears below - I'd like this behavior to happen without a manual refresh
App.tsx
import React, {useState, useEffect} from "react"
import './App.css';
import APIHelper from "./APIHelper";
function App() {
const [todos, setTodos] = useState([])
const [todo, setTodo] = useState("")
useEffect(() => {
const fetchTodoAndSetTodos = async () => {
const todos = await APIHelper.getAllTodos()
setTodos(todos)
}
fetchTodoAndSetTodos()
}, [])
const createTodo = async (e: { preventDefault: () => void; }) => {
e.preventDefault()
const newTodo = await APIHelper.createTodo(todo)
// @ts-ignore
setTodos([...todos, newTodo])
}
return (
<div className="App">
<div>
<input
id="todo-input"
type="text"
value={todo}
onChange={({target}) => setTodo(target.value)}
/>
<button type="button" onClick={createTodo}>
Add
</button>
</div>
<ul>
{todos.map(({_id, task, completed}, i) => (
<li
key={i}
className={completed ? "completed" : ""}
> {task}
</li>
))}
</ul>
</div>
)
}
export default App
APIHelper.js
import axios from "axios"
const API_URL_GET = "http://localhost:8080/"
const API_URL_CREATE = "http://localhost:8080/create"
async function createTodo(task) {
const { data: newTodo } = await axios.post(API_URL_CREATE, {
task,
})
return newTodo
}
async function getAllTodos() {
const { data: todos } = await axios.get(API_URL_GET)
return todos
}
export default { createTodo, getAllTodos }
[1]: https://i.sstatic.net/CuYUK.png
[2]: https://i.sstatic.net/PDne4.png
Upvotes: 0
Views: 188
Reputation: 1259
For me it seems like that APIHelper.createTodo
returns a wrong object. The list item is at the screen, but has no task
property.
As mentioned above, Try to prevent forceUpdate() the component.
async function createTodo(task) {
const { data: newTodo } = await axios.post(API_URL_CREATE, {
task,
});
// check this newTodo value
return newTodo
}
To reset the input
field, setTodo("")
to an empty string
Upvotes: 0
Reputation: 2276
Normally you should avoid this but still here you go you can using forceUpdate
In your component, you can call this.forceUpdate()
to force a rerender.
Documentation: https://facebook.github.io/react/docs/component-api.html
Upvotes: 0
Reputation: 4008
Inside the createTodo
function, you'll need to reset your todo
state.
Which means setting it to an empty string again:
const createTodo = async (e: { preventDefault: () => void; }) => {
// ...
setTodo(''); // Here
}
Upvotes: 1