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

React无刷新渲染笔记:是否需合并CreateArea与Note组件?

问题:React笔记应用添加/删除后需刷新才显示,组件拆分下如何处理?

我是React新手,开发了一个允许用户创建笔记的Web应用,笔记存入数据库,通过fetch和useEffect()渲染。纯前端时可以用下面的代码直接更新笔记:

function addNote(newNote) {
  setNotes(prevNotes => {
    return [...prevNotes, newNote];
  });
}

但接入数据库后,添加新笔记必须刷新页面才能显示。我知道可以在操作后重新获取数据,但相关逻辑拆分在CreateArea和Note两个组件里,不知道怎么配置,也没法用useEffect实现。请问我需要合并这两个组件吗?


我的组件代码:

CreateArea组件

import React, { useState, useEffect } from "react";
import Header from "./Header";
import Footer from "./Footer";
import Category from "./Category";
import Note from "./Note";
import axios from "axios"

function CreateArea(props) {
const [isExpanded, setExpanded] = useState(false);
const [categories, setCategories] = useState([])
const [notes, setNotes] = useState([])

const [note, setNote] = useState({
title: "",
content: "",
category: ''
  });

function handleChange(event) {
const { name, value } = event.target;
console.log("handleChange called")
setNote(prevNote => {
return {
        ...prevNote,
        [name]: value
      };
    });
  }

function submitNote(e){
      e.preventDefault();
      axios.post("http://localhost:5000/notes/add-note", note)
           .then((res) => {
      setNote({
      category: '',
      title: "",
      content: ""
              })
              

      console.log("Note added successfully");
      console.log(note)
            })
            .catch((err) => {
      console.log("Error couldn't create Note");
      console.log(err.message);
            });

        }


    function expand() {
    setExpanded(true);
      }



      return (
      <div>
          <Header/>
          <Category/>
            <form className="create-note">
      {isExpanded && (
                <input
      name="title"
      onChange={handleChange}
      value={note.title}
      placeholder="Title"
      />
              )}
              <textarea
      name="content"
      onClick={expand}
      onChange={handleChange}
      value={note.content}
      placeholder="Take a note..."
      rows={isExpanded ? 3 : 1}
      />
                <select
                name="category"
      onChange={handleChange}
      value={note.category}>
      {
                      categories.map(function(cat) {
      return <option
      key={cat.category} value={cat.value} > {cat.category} </option>;
                      })
      }
      </select>

              <button onClick={submitNote}>Add</button>
      </form>
      <Note/>
            <Footer/>
      </div>
        );
      }
export default CreateArea;

Note组件

import React, {useState,useEffect} from "react";
import axios from "axios";

function Note(props) {
  const [notes, setNotes] = useState([])

  useEffect(() => {
    fetch('http://localhost:5000/notes')
    .then(res => res.json())
  .then(json => {console.log(json)
    setNotes(json)})
  }, [])

  function deleteNote(id) {
    axios.delete(`http://localhost:5000/notes/${id}`)
    .then(() => { console.log("Note successfully deleted")});
  }

return (
  <div>
  {notes.map((noteItem, index) => {
    return (
        <div className="note">
       <h1>{noteItem.title}</h1>
       <p>{noteItem.content}</p>
       <button onClick={() => {deleteNote(noteItem._id)}}>
         Delete
       </button>
       <p>{noteItem.category}</p>
     </div>
  
    );
  })}
  </div>
)
  }
  
  export default Note

解决方案:用状态提升实现组件间数据同步

不需要合并组件,React的状态提升就能解决这个问题,核心思路是把共享的笔记列表状态放到父组件中,子组件通过props获取状态和更新方法:

步骤1:修改CreateArea组件,接管笔记状态和数据逻辑

把Note组件里的notes状态、数据获取逻辑移到CreateArea,同时添加操作后刷新数据的逻辑:

import React, { useState, useEffect } from "react";
import Header from "./Header";
import Footer from "./Footer";
import Category from "./Category";
import Note from "./Note";
import axios from "axios"

function CreateArea(props) {
const [isExpanded, setExpanded] = useState(false);
const [categories, setCategories] = useState([])
const [notes, setNotes] = useState([]) // 接管笔记列表状态

const [note, setNote] = useState({
title: "",
content: "",
category: ''
  });

// 封装获取笔记的方法,方便重复调用
const fetchNotes = () => {
  fetch('http://localhost:5000/notes')
    .then(res => res.json())
    .then(json => setNotes(json))
    .catch(err => console.log("获取笔记失败", err))
}

// 组件挂载时初始化笔记列表
useEffect(() => {
  fetchNotes();
}, [])

function handleChange(event) {
const { name, value } = event.target;
setNote(prevNote => {
return {
        ...prevNote,
        [name]: value
      };
    });
  }

function submitNote(e){
      e.preventDefault();
      axios.post("http://localhost:5000/notes/add-note", note)
           .then((res) => {
      setNote({
      category: '',
      title: "",
      content: ""
              })
      // 添加成功后刷新笔记列表
      fetchNotes();
      console.log("Note added successfully");
            })
            .catch((err) => {
      console.log("Error couldn't create Note");
      console.log(err.message);
            });
        }

// 封装删除方法,传给Note组件调用
const deleteNote = (id) => {
  axios.delete(`http://localhost:5000/notes/${id}`)
    .then(() => {
      console.log("Note successfully deleted");
      // 删除成功后刷新笔记列表
      fetchNotes();
    })
    .catch(err => console.log("删除笔记失败", err))
}

    function expand() {
    setExpanded(true);
      }

      return (
      <div>
          <Header/>
          <Category/>
            <form className="create-note">
      {isExpanded && (
                <input
      name="title"
      onChange={handleChange}
      value={note.title}
      placeholder="Title"
      />
              )}
              <textarea
      name="content"
      onClick={expand}
      onChange={handleChange}
      value={note.content}
      placeholder="Take a note..."
      rows={isExpanded ? 3 : 1}
      />
                <select
                name="category"
      onChange={handleChange}
      value={note.category}>
      {
                      categories.map(function(cat) {
      return <option
      key={cat.category} value={cat.value} > {cat.category} </option>;
                      })
      }
      </select>

              <button onClick={submitNote}>Add</button>
      </form>
      {/* 把笔记列表和删除方法传给Note组件 */}
      <Note notes={notes} deleteNote={deleteNote}/>
            <Footer/>
      </div>
        );
      }
export default CreateArea;

步骤2:修改Note组件,通过props接收状态和方法

去掉组件内部的状态和useEffect,直接使用父组件传递的数据:

import React from "react";

function Note(props) {
return (
  <div>
  {props.notes.map((noteItem) => {
    return (
        <div className="note" key={noteItem._id}> {/* 用数据库返回的_id作为唯一key */}
       <h1>{noteItem.title}</h1>
       <p>{noteItem.content}</p>
       <button onClick={() => props.deleteNote(noteItem._id)}>
         Delete
       </button>
       <p>{noteItem.category}</p>
     </div>
  
    );
  })}
  </div>
)
  }
  
  export default Note

额外优化建议

  • 给列表项使用数据库返回的_id作为key,避免React渲染警告
  • 可以添加加载状态,在fetchNotes执行时显示加载提示,提升用户体验
  • 如果后端在添加/删除接口返回最新的笔记数据,可直接用返回值更新状态,减少一次GET请求,例如:
    // 添加笔记时直接用返回的新笔记更新列表
    axios.post("http://localhost:5000/notes/add-note", note)
      .then(res => {
        setNotes(prev => [...prev, res.data])
        // ...其他逻辑
      })
    

内容的提问来源于stack exchange,提问作者01nowicj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 20:05:23