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
相关产品推荐
相关产品推荐

