为什么不使用useEffect再运行我的API提取并保存结果到状态?

时间:2019-06-17 19:14:19

标签: javascript wordpress reactjs react-hooks wp-api

目标:

请注意,所使用的示例并非我项目的确切上下文,而是非常相似的,因此出于本文的考虑而简化

我正在尝试使用WP-API来使用Wordpress类别,帖子标题和帖子内容来生成动态React应用。

每条信息都在React应用程序的生成中发挥作用:

  • Wordpress类别用于在React App中填充侧边栏导航组件。每个Wordpress类别将在此导航中充当项目。将此组件视为目录。

  • 帖子标题将成为每个类别的子菜单项。因此,以食谱为例,如果菜单上的类别项目之一是“墨西哥菜”,则帖子标题或子菜单项可能是“炸玉米饼”,“辣酱玉米饼馅”,“炸玉米饼”。

    < / li>
  • 以墨西哥美食为例,帖子内容将显示在主要内容区域,具体取决于您单击的子菜单项。因此,如果单击侧栏菜单组件中的“炸玉米饼”,则主要内容将填充“炸玉米饼”的配方。这个主要的内容区域是其自己的独立组件。

问题:

主要问题是,使用React钩子,useEffect和fetch,我能够在侧栏导航组件上填充项目,而没有太多问题。但是,一旦单击子菜单项,该配方就不会填充到主要内容区域。

研究发现:

我能够确定useEffect无法设置我的状态。我声明了两个变量,这些变量处理通过获取WP-API获得的JSON数据。然后,我想使用setPost函数将结果设置为组件状态。但是,此setPost函数不会设置状态。下面,为清楚起见,我将发布代码示例。

代码:

这是我当前的主要内容组件,用于接收道具。具体来说,它从React Router接收“ match”道具,其中包含特定WordPress帖子的URL链接。我用这个

import React, { useState, useEffect } from 'react'

function MainContent(props) {
    console.log(props)

    useEffect(() => {
        fetchPost()
    }, [])

    const [post, setPost] = useState([])

    const fetchPost = async () => {
        console.log('Fetched Main Content')
        const fetchedPost = await fetch(`http://coolfoodrecipes.xyz/wp-json/wp/v2/posts?slug=${props.match.params.wpslug}`)
        const postContent = await fetchedPost.json()
        console.log(postContent[0])

        setPost(postContent[0])
        console.log(post)
    }

    return (
        <div>
            {/* <h1 dangerouslySetInnerHTML={{__html: post.title.rendered}}></h1> */}
        </div>
    )
}

export default MainContent

这是第一个控制台日志的结果,其中包含我的比赛道具的内容:

{
isExact: true,
params: {wpslug: "tacos"},
path: "/:wpslug",
url: "/tacos"
}

我的第三个控制台日志console.log(postContent[0])的结果导致一个对象,在该对象中它正确返回该特定帖子的每个细节。

此后,我使用setPost(postContent[0])将此信息保存到我的post状态。

要确认这一点,我运行console.log(post),它返回一个简单的[],一个空数组。

结果与预期

我期望setPost(postContent[0])中的内容可以正确保存为post状态,以便我可以使用该内容在页面上呈现内容。

但是,实际结果是什么都没有保存到状态,并且每当我单击其他类别(例如“ Tamales”或“ Enchiladas”)时,URL都会更新,但是在第一次获取。

我知道这是一个漫长的问题,但是任何可以帮助这个可怜的新手的人都是绝对的救星!预先感谢!

3 个答案:

答案 0 :(得分:0)

setPost也是异步的,就像Component类的普通setState一样。 所以你应该使用

await setPost(postContent[0])
console.log(post)

在函数内部获取结果

答案 1 :(得分:0)

也许尝试将const postContent = await fetchedPost.json()更改为const postContent = await fetchedPost.data

答案 2 :(得分:0)

首先,让我们看一下您的第二个问题/期望:它在第一次获取后就永远不会获取信息。

useEffect函数可能具有两个参数。回调函数和一组依赖项。仅当其依赖项之一发生更改时,才会调用effect函数。如果省略第二个参数,则该函数将在每次重新渲染时运行。 您的数组为空;这意味着效果将在首次安装组件时运行,此后将不会重新运行。

要解决该问题,您需要正确添加依赖项。 如果您遇到props.match.params.wpslug更改的情况,则要重新获取。

useEffect(() => {
        fetchPost()
}, [props.match.params.wpslug])

现在出现了看似无法正确设置状态的问题。 在您的示例中,设置/更新状态似乎没有错。 问题在于'post'变量是针对当前渲染周期已设置为[]的变量,直到下一个周期才会更改(您应该并且确实将其标记为const,因此它无法更改其值)。

我将在这里解释2个周期。

/* First run, should be the mounting of the component */
function MainContent(props) {
    const slug = props.match.params.wpslug;
    const [post, setPost] = useState([]) // 1. post is currently []

    useEffect(() => { // 3. the useEffect callback will be called, i.e. fetching posts
        fetchPost()
    }, [slug])

    const fetchPost = async () => {
        const fetchedPost = await fetch(`http://coolfoodrecipes.xyz/wp-json/wp/v2/posts?slug=${slug}`)
        const postContent = await fetchedPost.json()

        // 4. you change the state of this component, 
        // React will run the next render-cycle of this component
        setPost(postContent[0]) 
    }

    return (
        <div>
            <h1>{post.title}</h1> {/* 2. React will tell the browser to render this */}
        </div>
    )
}
/* Second run, initiated by setting the post state */
function MainContent(props) {
    const slug = props.match.params.wpslug;
    const [post, setPost] = useState([]) // 1. post is now [{title: 'TestPost'}]

    useEffect(() => { // on this cycle this useEffect callback will not run because 'slug' did not change
        fetchPost()
    }, [slug])

    const fetchPost = async () => {
        const fetchedPost = await fetch(`http://coolfoodrecipes.xyz/wp-json/wp/v2/posts?slug=${slug}`)
        const postContent = await fetchedPost.json()

        setPost(postContent[0]) 
    }

    return (
        <div>
            <h1>{post[0].title}</h1> {/* 2. React will tell the browser to render this */}
        </div>
    )
}

此处(https://overreacted.io/a-complete-guide-to-useeffect/)是有关新的useEffect Hook的非常有趣的文章,您遇到的一些问题已得到解决。