简体   繁体   中英

How can I prevent states from resetting after a http request?

when I send the server an HTTP request ( patch request in the checkbox onChange function) and update the state other states will be deleted until I reload the page and they will be back so how can I update the states without losing the others? I'm not totally sure but I think the problem is where I'm updating the state with the response I get from the server I think I'm not updating the state and I'm just adding the new response to it and replacing the others

here's my code



const Form = () => {
  const [todos, setTodos] = React.useState([]);

  const debounce = (func, timeout = 350) => {
    let timer;
    return (...args) => {
      clearTimeout(timer);
      timer = setTimeout(() => {
        func.apply(this, args);
      }, timeout);
    };
  };
  const saveInput = (e, id) => {
    const x = !e.target.checked;
    console.log(x);

    axios
      .patch(`http://127.0.0.1:8000/todo/todos/${id}/`, {
        completed: x,
      })
      .then(
        (response) => {
          console.log(response.data);

          setTodos([response.data]);
        },
        (error) => {
          console.log(error);
        }
      );
  };
  const processChange = debounce((e, id) => saveInput(e, id));

  useEffect(() => {
    axios.get("http://127.0.0.1:8000/todo/todos/").then((response) => {
      setTodos(response.data);
    });
  }, []);

  return (
    <form>
      <h1>Todo list</h1>
      <button>Add</button>
      <div>
       
          {todos.map((todo) => (
            <ul key={todo.id}>
              <li>{todo.title}</li>
              <li>{todo.description}</li>
              <button onClick={() => deleteHandler(todo.id)}>delete</button>
              <input
                type="checkbox"
                placeholder="completed"
                onChange={(e) => processChange(e, todo.id)}
                checked={todo.completed}
              />
            </ul>
          ))}
       
      </div>
    </form>
  );
};

export default Form;

Try This.

const saveInput = (e, id) => {
const x = !e.target.checked;
console.log(x);
const newTodos = [...todos];
const filteredTodos = newTodos.filter(todo => todo.id !== id);
axios
  .patch(`http://127.0.0.1:8000/todo/todos/${id}/`, {
    completed: x,
  })
  .then(
    (response) => {
      console.log(response.data);
      filteredTodos.push(response.data);
      setTodos(filteredTodos);
    },
    (error) => {
      console.log(error);
    }
  );

};

Inside your saveInput function you are resetting your todos with the new response data. Thus you are losing the data from your component initialization. What you need to do is to destructure your existing data and add them with your new payload.

You can either do this:

setTodos([...todos, response.data]);

Or this:

setTodos((prevState) => ([...prevState, response.data]))

The second option is the best practice as this returns your state correctly. Hope this helps.

So Morteza's answer worked but it had a tiny problem which was when i updated the state the order of the state ( array ) would change because of .push() method which pushes the item to the last index here is the solution which works fine and won't change the orders:

setTodos(val => val.map(item => item.id === response.data.id ? (response.data) : item));

It's getting the todos current state, mapping and checking if each of its item.id is equal to the item.id from the server and if it is, then replaced and updated with a response.data , if not then nothing changes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM