You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:无法通过React Hooks更新JSONPlaceholder数据

React Hooks + Fetch PUT更新JSONPlaceholder数据问题修复

问题根源分析

  1. Update组件无本地状态管理:未跟踪用户输入的修改值,表单提交时无法正确获取最新输入
  2. 参数传递与请求体错误:onUpdate函数参数格式不匹配,PUT请求体写死字符串而非变量
  3. 父组件状态未同步:PUT请求成功后未更新App组件的users数组,页面无法刷新显示修改后的数据
  4. 表单提交逻辑错误:Update组件表单未绑定onSubmit,按钮未触发提交,输入框无初始值
  5. 组件方法传递遗漏:Album组件未将App的onUpdate传递给Update组件,导致无法触发全局状态更新

修改后的完整代码

App.js

import './App.css';
import Create from "./Create";
import Album from "./Album";
import { useState, useEffect } from 'react'

function App() {
  const [users, setData] = useState([]);

  useEffect(() => {
    fetchData();
  }, []);

  const fetchData = async () => {
    await fetch("https://jsonplaceholder.typicode.com/albums")
      .then((res) => res.json())
      .then((data) => setData(data))
      .catch((err) => console.log(err));
  };

  const onAdd = async (title, userId) => {
    const url = "https://jsonplaceholder.typicode.com/albums/"
    await fetch(url, {
      method: "POST",
      body: JSON.stringify({ title, userId }),
      headers: { "Content-type": "application/json; charset=UTF-8" },
    })
      .then((res) => res.status === 201 && res.json())
      .then((data) => data && setData(prev => [...prev, data]))
      .catch((err) => console.log(err));
  };

  // 修改onUpdate:接收id、title、userId,请求成功后更新本地状态
  const onUpdate = async (id, title, userId) => {
    fetch(`https://jsonplaceholder.typicode.com/albums/${id}`, {
      method: 'PUT',
      body: JSON.stringify({ title, userId, id }), // 携带id确保接口返回正确数据
      headers: { 'Content-type': 'application/json; charset=UTF-8' },
    })
      .then((response) => response.json())
      .then((updatedItem) => {
        // 更新users数组中对应id的项
        setData(prevUsers => prevUsers.map(item => 
          item.id === id ? updatedItem : item
        ));
      })
      .catch((err) => console.log(err));
  };

  const onDelete = async (id) => {
    await fetch(`https://jsonplaceholder.typicode.com/albums/${id}`, { // 修正接口路径:users改为albums
      method: "DELETE",
    })
      .then((res) => {
        if (res.status === 200) {
          setData(users.filter(item => item.id !== id));
        }
      })
      .catch((err) => console.log(err));
  };

  return (
    <div className="App">
      <h3>React Crud Using Jsonplaceholder</h3>
      <br />
      <Create onAdd={onAdd} />
      <h3>There are total {users.length} albums </h3>
      <div>
        {users.map((item) => (
          <Album
            id={item.id}
            key={item.id}
            title={item.title}
            userId={item.userId}
            onDelete={onDelete}  
            onUpdate={onUpdate} // 传递onUpdate方法
          />         
        ))}
      </div>
    </div>
  );
};

export default App;

Update.js

import { useState, useEffect } from 'react'

export default function Update({ id, initialUserId, initialTitle, onUpdate }){   
  // 本地状态跟踪输入值
  const [userId, setUserId] = useState('');
  const [title, setTitle] = useState('');

  // 初始化输入框值为传入的原始数据
  useEffect(() => {
    setUserId(initialUserId.toString());
    setTitle(initialTitle);
  }, [initialUserId, initialTitle]);

  const handleOnSubmit = (e) => {
    e.preventDefault();
    // 调用父组件传递的onUpdate,传递正确参数
    onUpdate(id, title, parseInt(userId));
    // 清空输入框
    setTitle('');
    setUserId('');
  }

  return(
    <div>
      <form onSubmit={handleOnSubmit}>
        <h3>Update Album</h3>
        <input  
          name="userId"               
          type="number" 
          placeholder="userId"
          value={userId}
          onChange={(e) => setUserId(e.target.value)} 
        />
        
        <input  
          name="title"
          type="text"
          placeholder="title" 
          value={title}
          onChange={(e) => setTitle(e.target.value)}
        />
        <button type="submit">Update</button>
        <hr />
      </form>
    </div>
  )
}   

Album.js

import { useState } from 'react'
import Update from './Update'

export default function Album({ id, title, userId, onDelete, onUpdate }){
  const handleDelete = () => onDelete(id);
  const [showUpdate, setShowUpdate] = useState(false);

  return (
    <div className="albumArt">
      <h2>{title}</h2>
      <p>{userId}</p>
      <span>
        <button onClick={() => setShowUpdate(!showUpdate)}>edit</button>
        <button onClick={handleDelete}>delete</button>
      </span>
      
      {/* 传递初始值和父组件的onUpdate */}
      {showUpdate && <Update 
        id={id} 
        initialUserId={userId} 
        initialTitle={title} 
        onUpdate={onUpdate} 
      />}
    </div>
  )
}

Create.js

export default function Create({ onAdd }){
  const handleOnSubmit = (e) => {
    e.preventDefault();
    onAdd(e.target.title.value, parseInt(e.target.userId.value));
    e.target.title.value = "";
    e.target.userId.value = "";
  }

  return(
    <div>
      <form onSubmit={handleOnSubmit}>
        <h3>Add Album</h3>
        <input placeholder="title" name="title" />
        <input placeholder="userId" name="userId" type="number" />
        <button type="submit">Add</button>
        <hr />
      </form>
    </div>
  )
}

关键修复点说明

  • Update组件新增本地状态:用useState跟踪输入框的title和userId,确保能获取用户修改的内容
  • 修正onUpdate参数与请求体:App中的onUpdate接收三个参数,请求体使用变量而非固定字符串,成功后通过map更新users数组对应项
  • 同步组件间方法传递:Album组件将App的onUpdate传递给Update,确保修改能触发全局状态更新
  • 完善表单逻辑:Update组件表单绑定onSubmit,按钮设置type="submit",输入框绑定value和onChange,并通过useEffect初始化显示原始数据
  • 修正删除接口路径:原代码删除请求错用了users接口,改为albums接口

内容的提问来源于stack exchange,提问作者Sai Sri Laxman Jangala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 10:45:27