0

I have been struggling to understand what is going wrong with this simple todo list front end React app, which should interact with an express API.

my React code is:

import React, {Component} from 'react';

class App extends Component {

constructor(){
    super();

    this.state = { 
        todos:[],
        currentItem: ''
    };  
    this.handleChange = this.handleChange.bind(this);
    this.handleADDButton = this.handleADDButton.bind(this);
    this.deleteItem = this.deleteItem.bind(this);
    this.updateTodo = this.updateTodo.bind(this);
}

componentDidMount(){
    fetch('http://ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com:3001/list')
    .then(res => res.json())
    .then((todosList) =>
        {this.setState({'todos': todosList});
        });
}

handleChange(event){
    this.setState({currentItem: event.target.value});
}

handleADDButton(event){
    fetch('http://ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com:3001/post', {
        method: 'POST',
        headers:{'Content-type': 'application/json'},
        body: JSON.stringify({title: this.state.currentItem})
    });
}

deleteItem(x){
    fetch('http://ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com:3001/' + x, {
        method: 'DELETE',
        headers:{'Content-type': 'application/json'}
        })
      }

updateTodo(y){
    fetch('http://ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com:3001/' + y, {
        method: 'PUT',
        headers:{'Content-type': 'application/json'},
        body: JSON.stringify({title: this.state.currentItem})
        })
    }

render() {
    return(
        <div>
         <h1> Todo List </h1> 
          <ul>
        {this.state.todos.map((todo) => <li> {todo.title}
                    <button type="button" onClick={() => this.deleteItem(todo.key)} >x</button> 
        <button type="button" onClick={() => this.updateTodo(todo.key)}>update</button> </li>)}
          </ul>
            <input type="text" value={this.state.currentItem} onChange={this.handleChange} />
            <button type="submit" onClick={this.handleADDButton}>ADD</button>

            </div>
        )
 }
}
export default App

The calls do update the API, and if I manually refresh the page, the React app picks up on the new data coming through from the API. However, when clicking the buttons it doesn't re-render by itself.

Say for example I click the ADD Button. It sends an OPTIONS to which I get back a 200 code, a POST which also comes back with a 200 and only sometimes, a GET with a 200. There is no pattern in when it performs the last GET call and also there is no pattern in when it re-renders following a button click. To obtain the latest data I always have to refresh.

Don't know what to make of this and have been stuck for days.

  • 1
    I dont see any state updates in button click actions – Kalhan.Toress Jun 17 '20 at 10:15
  • can you do this: `.then(res => res.json()).then(res => console.log(res)` and show me what it shows – Red Baron Jun 17 '20 at 10:15
  • 1
    If i click Add and it will call this.handleADDButton inside that after fetch completes there is no state updates – Kalhan.Toress Jun 17 '20 at 10:16
  • 1
    You are not making a get request anywhere other than componentDidMount. Also you have a button type submit which will lead to a refresh on your page on submit. Ideally you should use the response of POST/PUT/DELETE request to update your localState – Shubham Khatri Jun 17 '20 at 10:18
  • I would strongly recommend learning [arrow functions](https://scrimba.com/p/p4Mrt9/c7vd3cd) and [hooks](https://scrimba.com/course/greacthooks) particularly the `useState` hook – Sam Jun 17 '20 at 10:30

2 Answers2

0

I think there is no state update on button actions

try to add a state updates for the actions same as componentDidMount

For ex:

handleADDButton(event){
    event.preventDefault();
    fetch('http://ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com:3001/post', {
        method: 'POST',
        headers:{'Content-type': 'application/json'},
        body: JSON.stringify({title: this.state.currentItem})
    }).then(res => res.json())
    .then((data) => {            
        this.setState((prevState) {
            const todos = [...prevState.todos, data.todo];
            return {
                todos: todos
            }
        })
    });
}

In this case you have to return the new todo which will catch in data.todo


And for delete action

deleteItem(x){
    fetch('http://ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com:3001/' + x, {
        method: 'DELETE',
        headers:{'Content-type': 'application/json'}
    }).then(res => res.json())
    .then((data) => {           
        this.setState((prevState) {
            const newTodos = prevState.todos.filter(t => t.key !== x);
            return {
                todos: newTodos
            };
        })
    });
  }

These codes are not tested.

Kalhan.Toress
  • 21,683
  • 8
  • 68
  • 92
  • Hi Kalhan, what is prevState in your code? I suppose it would be {this.state.todos} in my case? – Antonio Marchi Jun 17 '20 at 12:31
  • correct, prevState is current state right before it gets update, check this out: https://stackoverflow.com/questions/42038590/when-to-use-react-setstate-callback – Kalhan.Toress Jun 17 '20 at 12:40
  • 1
    it works! the concept of prevState was new to me and your comments and direction with that link helped me a lot! I come from a non programming background and today you helped a lot! Thank you very much Kalhan, have a wonderful day. – Antonio Marchi Jun 18 '20 at 11:03
  • No worries, happy leaning :) – Kalhan.Toress Jun 18 '20 at 19:07
0

actually you don't have any state update in your code. you have to use "setState" when fetching data from API. I recommended learning arrow function and Hooks and use somethings like AXIOS to manage API calls.

shahryar ab
  • 71
  • 1
  • 2
  • 7