如何将 useEffect() 中定义的函数传递给 reactjs 中的子组件?

How to pass a function defined in useEffect() to a child component in reactjs?

Here 我了解到,由于 filter 常量,我需要将 fetcProjects 函数移到 useEffect() 中。说得通。但是因此我无法在 AddProject 组件中使用该功能。我得到 'fetchProjects' is not defined.

我会在 useEffect() 之外重新定义函数,但这对我来说没有意义,需要定义两次。

import React, { useState, useEffect } from 'react'
import axios from 'axios'
import '../sass/Projects.sass'
import ProjectsList from './ProjectsList'
import Search from './Search'
import AddProject from './AddProject'

function Projects() {

    const [isLoading, setIsLoading] = useState(true)
    const [projects, setProjects] = useState([])
    const [filter, setFilter] = useState('')

    useEffect(() => {
        const fetchProjects = async () => {
            try {
                const result = await axios(`/api/projects?name=${filter}`)
                setProjects(result.data.data)
                setIsLoading(false)
            } catch (error) {
                console.log(error);
            }
        }
        fetchProjects();
    }, [filter]);

    return (
        <div className="container">
            <Search getFilter={(f) => setFilter(f)} />
            <AddProject fetchProjects={fetchProjects} />
            <p>&nbsp;</p>
            <ProjectsList projects={projects} isLoading={isLoading} />
        </div>
    )
}

export default Projects;

我认为你可以在 useEffect 之外定义 fetchProjects 并将过滤器常量作为回调的参数传递给它,就像这样

useEffect(() => fetchProjects(filter), [filter])

尝试一下,如果有效请告诉我

编辑:所以看起来你这样做是出于 best-practices 之类的原因,在那种情况下(假设你已经准备好了),你需要找到一种方法,根据你的规则,比如简单地在子组件中定义一个函数来做类似的事情。

您至少有 三个 doh! 四个选项:

  1. 将函数置于状态或引用中。 (Yuck)(请注意,将其置于状态中你必须将其包装在一个对象中,否则状态 setter 将变得混乱并尝试调用它。)

  2. 避免在 useEffect 回调中定义函数。 (这在技术上可以通过使用 setFilter(filter => /*...*/),但它也很令人讨厌。)

  3. 使用useMemo代替useEffect

  4. 参数化函数,使其 接受 filter 作为参数,而不是像 那样关闭它。

其中,#3 和#4 似乎是您的最佳选择。这是 #3 的样子:

function Projects() {

    const [isLoading, setIsLoading] = useState(true);
    const [projects, setProjects] = useState([]);
    const [filter, setFilter] = useState('');

    const fetchProjects = useMemo(
        () => {
            const fetchProjects = async () => {
                try {
                    const result = await axios(`/api/projects?name=${filter}`);
                    setProjects(result.data.data);
                    setIsLoading(false);
                } catch (error) {
                    console.log(error);
                }
            };
            fetchProjects();
            return fetchProjects;
        },
        [filter]
    );

    fetchProjects();

    return (
        <div className="container">
            <Search getFilter={(f) => setFilter(f)} />
            <AddProject fetchProjects={fetchProjects} />
            <p>&nbsp;</p>
            <ProjectsList projects={projects} isLoading={isLoading} />
        </div>
    )
}

每当 filter 发生变化时都会重新创建 fetchProjects,并且(大多数情况下)不会在它不发生变化时重新创建。 (useMemo 可以 运行 创建回调,即使依赖关系没有改变,但通常不会。)

这是 的 #4 的更完整示例。这将 fetchProjects 完全移出组件,将 setter 传递给它以使用:

const fetchProjects = async (filter, setProjects, setIsLoading) => {
    try {
        const result = await axios(`/api/projects?name=${filter}`);
        setProjects(result.data.data);
        setIsLoading(false);
    } catch (error) {
        // *** You probably want to setIsLoading(false) here...?
        // And probably show the user that an error occurred.
        console.log(error);
    }
};

function Projects() {

    const [isLoading, setIsLoading] = useState(true);
    const [projects, setProjects] = useState([]);
    const [filter, setFilter] = useState('');

    useEffect(() => {
        fetchProjects(filter, setProjects, setIsLoading);
    }, [filter]);

    return (
        <div className="container">
            <Search getFilter={(f) => setFilter(f)} />
            <AddProject fetchProjects={() => fetchProjects(filter, setProjects, setIsLoading)} />
            <p>&nbsp;</p>
            <ProjectsList projects={projects} isLoading={isLoading} />
        </div>
    );
}