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

MERN栈中如何携带新参数发起GET请求实现数据筛选并无刷新更新?

问题解决与实现方案

一、解决Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body错误

原因分析

GET/HEAD请求的HTTP规范不允许携带请求体(body),你当前后端filterProject函数从req.body读取参数,同时路由配置为GET /filter,如果前端用GET请求携带body就会触发该错误。以下是两种可行修改方案:


方案1:改用POST请求(适配现有代码)

后端修改

  1. 修改路由文件,将GET /filter改为POST /filter:
// 路由文件
// 替换原有GET /filter路由
router.post('/filter', filterProject)
  1. 后端filterProject函数无需修改(已从req.body取参)

前端修改

通过父子组件传值,让Dropdown提交时调用父组件的筛选请求函数:

  • 修改FilterBody组件,新增筛选请求函数并传递给Dropdown:
// Filterpage.js
const FilterBody = () => {
    const [projects, setProjects] = useState(null)

    // 新增:获取筛选后的项目数据
    const fetchFilteredProjects = async (filterData) => {
        const response = await fetch('/api/projects/filter', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(filterData)
        })
        const json = await response.json()
        if (response.ok) {
            setProjects(json)
        }
    }

    useEffect(() => {
        const fetchProjects = async () => {
            const response = await fetch('/api/projects')
            const json = await response.json()
            if (response.ok) {
                setProjects(json)
            }
        } 
        fetchProjects()
    }, [])

    return (
        <div className="filterHome">
            <div className="filterTableContainer">
                <div className="filterTableTitle">
                    Filter Table
                </div>
                <div className="filterSDGDropDown">
                    {/* 传递筛选函数给Dropdown */}
                    <Dropdown onFilterSubmit={fetchFilteredProjects} />
                </div>
            </div>

            {/* 项目列表部分保持不变 */}
            <div>
                <div className="projects">
                    {projects && projects.map((project) => (
                        <ProjectDetails key={project._id} project={project}/>
                    ))}
                </div>
            </div>
        </div>
    )
}
  • 修改Dropdown组件的handleSubmit方法,调用父组件传来的函数:
// Dropdown.js
// 修改handleSubmit方法
handleSubmit(event) {
    event.preventDefault();
    const { sdg, assignment_type, theme } = this.state;
    // 触发父组件的筛选请求
    this.props.onFilterSubmit({ sdg, assignment_type, theme });
}

方案2:使用GET请求的查询参数(符合REST语义)

如果希望保持GET请求(筛选属于数据查询操作,GET语义更匹配),可以将参数放在URL的查询字符串中:

后端修改

  1. 保持GET /filter路由不变,修改filterProject函数从req.query取参:
// controller中的filterProject函数
const filterProject = async (req, res) => {
    // 从查询字符串获取参数,替代req.body
    const {sdg, assignment_type, theme} = req.query
    const filteredProjects = await Project.find({sdg, assignment_type, theme})
    res.status(200).json(filteredProjects)
}

前端修改

修改FilterBody中的筛选请求函数,用查询字符串传递参数:

// Filterpage.js中的fetchFilteredProjects
const fetchFilteredProjects = async (filterData) => {
    // 将筛选参数转为查询字符串
    const searchParams = new URLSearchParams(filterData);
    const response = await fetch(`/api/projects/filter?${searchParams}`)
    const json = await response.json()
    if (response.ok) {
        setProjects(json)
    }
}

Dropdown组件的其他修改与方案1一致,调用父组件的fetchFilteredProjects即可。


二、React Context实现无刷新更新结果

完全可以用React Context实现,尤其适合后续组件层级加深、不想层层传递props的场景,具体实现步骤如下:

1. 创建Project Context

新建ProjectContext.js文件:

import { createContext, useContext, useState } from 'react';

const ProjectContext = createContext();

export const ProjectProvider = ({ children }) => {
    const [projects, setProjects] = useState(null);

    // 获取全部项目
    const fetchAllProjects = async () => {
        const response = await fetch('/api/projects');
        const json = await response.json();
        if (response.ok) {
            setProjects(json);
        }
    };

    // 获取筛选后的项目(示例用POST方案,也可替换为GET查询参数方案)
    const fetchFilteredProjects = async (filterData) => {
        const response = await fetch('/api/projects/filter', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(filterData)
        });
        const json = await response.json();
        if (response.ok) {
            setProjects(json);
        }
    };

    return (
        <ProjectContext.Provider value={{ projects, fetchAllProjects, fetchFilteredProjects }}>
            {children}
        </ProjectContext.Provider>
    );
};

// 自定义Hook,简化Context调用
export const useProjectContext = () => {
    return useContext(ProjectContext);
};

2. 在根组件中包裹Provider

比如在App.js中:

import { ProjectProvider } from './context/ProjectContext';

function App() {
    return (
        <ProjectProvider>
            {/* 包含FilterBody在内的所有子组件 */}
            <FilterBody />
        </ProjectProvider>
    );
}

3. 修改FilterBody组件使用Context

// Filterpage.js
import { useEffect } from 'react';
import { useProjectContext } from '../context/ProjectContext';
import ProjectDetails from '../ProjectDetails';
import Dropdown from './Dropdown';

const FilterBody = () => {
    const { projects, fetchAllProjects } = useProjectContext();

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

    return (
        <div className="filterHome">
            <div className="filterTableContainer">
                <div className="filterTableTitle">Filter Table</div>
                <div className="filterSDGDropDown">
                    <Dropdown />
                </div>
            </div>
            <div>
                <div className="projects">
                    {projects && projects.map((project) => (
                        <ProjectDetails key={project._id} project={project} />
                    ))}
                </div>
            </div>
        </div>
    );
};

export default FilterBody;

4. 修改Dropdown组件使用Context

将类组件改为函数组件,更方便使用Hook:

// Dropdown.js
import { useState } from 'react';
import { useProjectContext } from '../context/ProjectContext';

const Dropdown = () => {
    const { fetchFilteredProjects } = useProjectContext();
    const [sdg, setSdg] = useState('SDG 1: No Poverty');
    const [assignment_type, setAssignmentType] = useState('1');
    const [theme, setTheme] = useState('Demographic');

    const handleSubmit = (e) => {
        e.preventDefault();
        fetchFilteredProjects({ sdg, assignment_type, theme });
    };

    return (
        <form onSubmit={handleSubmit}>
            <label>SDG:</label>
            <select value={sdg} onChange={(e) => setSdg(e.target.value)}>
                <option value="SDG 1: No Poverty">SDG 1: No Poverty</option>
                <option value="SDG 2: Zero Hunger">SDG 2: Zero Hunger</option>
                <option value="SDG 3: Good Health & Well Being">SDG 3: Good Health & Well Being</option>
            </select>

            <label>Assignment Type:</label>
            <select value={assignment_type} onChange={(e) => setAssignmentType(e.target.value)}>
                <option value="1">1: Discussion Project</option>
                <option value="2">2: PDF Case study</option>
                <option value="3">3: Community Project</option>
            </select>

            <label>Theme:</label>
            <select value={theme} onChange={(e) => setTheme(e.target.value)}>
                <option value="Demographic">Demographic</option>
                <option value="Economical">Economical</option>
                <option value="Socio-cultural">Socio-cultural</option>
                <option value="Technological">Technological</option>
                <option value="Ecological">Ecological</option>
                <option value="Poltical">Poltical</option>
            </select>

            <input type="submit" value="Submit" />
        </form>
    );
};

export default Dropdown;

点击提交后,Context会自动更新projects状态,FilterBody中的项目列表会重新渲染,无需刷新页面。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 10:27:12