简体   繁体   English

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

[英]Why won't useEffect run my API fetch anymore and save results to state?

GOALS: 目标:

Note that examples used are not the exact context of my project, but are very similar, and therefore simplified for the sake of this post 请注意,所使用的示例并非我项目的确切上下文,而是非常相似的,因此出于本文的目的而进行了简化

I am trying to use WP-API to use Wordpress categories, post titles, and post content to generate a dynamic React app. 我正在尝试使用WP-API使用Wordpress类别,帖子标题和帖子内容来生成动态React应用程序。

Each piece of information plays a part in the generation of the React app: 每条信息都在React应用程序的生成中发挥着作用:

  • The Wordpress categories are used to populate a sidebar navigation component in the React App. WordPress类别用于在React App中填充侧栏导航组件。 Each Wordpress category will act as an item in this navigation. 每个Wordpress类别将在此导航中充当项目。 Think of this component as the table of contents. 将此组件视为目录。

  • The post titles will be submenu items to each category. 帖子标题将成为每个类别的子菜单项。 So, using recipes as an example, if one of the category items on the menu was "Mexican Food", the post titles, or submenu items, could be "Tacos", "Enchiladas", "Tamales". 因此,以食谱为例,如果菜单上的类别项目之一是“墨西哥菜”,则帖子标题或子菜单项可能是“炸玉米饼”,“辣酱玉米饼馅”,“玉米粉蒸肉”。

  • Sticking to the Mexican food example, the post content will be displayed in a main content area depending on which submenu item you click on. 继续以墨西哥美食为例,帖子内容将显示在主要内容区域,具体取决于您单击的子菜单项。 So, if you were to click on "Tacos" in the sidebar menu component, the main content would populate with the recipe for "Tacos". 因此,如果单击侧栏菜单组件中的“炸玉米饼”,则主要内容将填充“炸玉米饼”的配方。 This main content area is its own individual component. 该主要内容区域是其自己的单独组件。

PROBLEM: 问题:

The main problem is that I am able to get the items to populate on the sidebar navigation component without much issue using React hooks, useEffect, and fetch. 主要的问题是,使用React钩子,useEffect和fetch,我能够在侧栏导航组件上填充项目,而没有太多问题。 However, once I click on the submenu item, the recipe will not populate on the main content area. 但是,一旦单击子菜单项,该配方就不会填充到主要内容区域。

RESEARCH FINDINGS: 研究成果:

I was able to establish that useEffect is somehow not setting my state. 我能够确定useEffect无法设置我的状态。 I declare two variables which process the JSON data I get by fetching the WP-API. 我声明了两个变量,这些变量处理通过获取WP-API获得的JSON数据。 I then want to set the results into my component state using a setPost function. 然后,我想使用setPost函数将结果设置为组件状态。 However, this setPost function doesn't set the state. 但是,此setPost函数不会设置状态。 Below I'll post code examples for clarity. 为了清楚起见,下面我将发布代码示例。

CODE: 码:

This is my current Main Content component, which receives props. 这是我当前的主要内容组件,可接收道具。 Specifically, it receives the 'match' prop from React Router, which contains the URL slug for the specific WordPress post. 具体来说,它从React Router接收“ match”道具,其中包含特定WordPress帖子的URL链接。 I use this 我用这个

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

Here are the results of the 1st console log, which contains the contents of my match prop: 这是第一个控制台日志的结果,其中包含我的比赛道具的内容:

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

The result of my 3rd console log, console.log(postContent[0]) , results in an object where it returns every single piece of detail for that specific post correctly. 我的第三个控制台日志console.log(postContent[0])结果导致一个对象,在该对象中它正确返回该特定帖子的每个细节。

After that, I use setPost(postContent[0]) to save this information to my post state. 之后,我使用setPost(postContent[0])将此信息保存到我的post状态。

To confirm this, I run console.log(post) , to which it returns a simple [] , an empty array. 为了确认这一点,我运行console.log(post) ,它返回一个简单的[] ,一个空数组。

RESULTS & EXPECTATIONS: 结果与预期:

What I expected is that the content in setPost(postContent[0]) would be properly saved in the post state so that I could use that content to render content on the page. 我期望的是setPost(postContent[0])将正确保存在post状态,以便我可以使用该内容在页面上呈现内容。

However, the actual result is that nothing gets saved to the state, and any time I click on other categories, such as "Tamales", or "Enchiladas", the URL DOES update, but it never fetches information again after the first fetch. 但是,实际结果是什么都没有保存到状态,并且每当我单击其他类别(例如“ Tamales”或“ Enchiladas”)时,URL都会更新,但是在第一次获取后便再也不会获取信息。

I know this is a long winded question, but anyone who could help this poor newbie would be an absolute savior! 我知道这是一个漫长的问题,但是任何可以帮助这个可怜的新手的人都是绝对的救星! Thanks in advance! 提前致谢!

setPost is also asynchronous as is the normal setState of the Component class. setPost与Component类的常规setState也是异步的。 So you should use 所以你应该使用

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

to get the result inside your function 在函数内部获取结果

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

First let's take a look at your second problem/expectation: It never fetches information after the first fetch. 首先,让我们看一下您的第二个问题/期望:它在第一次获取后就永远不会获取信息。

The useEffect function may have two parameters. useEffect函数可以具有两个参数。 The callback function and an array of dependencies. 回调函数和一组依赖项。 The effect function will only be called when one of its dependencies changed. 仅当其依赖项之一发生更改时,才会调用effect函数。 If the second parameter is omitted the function will run on every re-render. 如果省略第二个参数,则该函数将在每次重新渲染时运行。 Your array is empty; 您的数组为空; that means the effect will run when the component is first mounted, after that it will not re-run. 这意味着效果将在首次安装组件时运行,此后将不会重新运行。

To resolve that problem you need to add your dependencies correctly. 要解决该问题,您需要正确添加依赖项。 In your case you want to re-fetch if props.match.params.wpslug changes. 在您的情况下,如果props.match.params.wpslug更改,您想重新获取。

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

Now for the problem of seemingly not setting the state correctly. 现在,看似无法正确设置状态的问题。 There seems to be nothing wrong with setting/updating state in your example. 在您的示例中,设置/更新状态似乎没有错。 The problem is the 'post' variable is for the current render-cycle already set to [] and will not change until the next cycle (you should and did mark it as const so it cannot change its value). 问题在于'post'变量是针对当前渲染周期已设置为[]的变量,直到下一个周期才会更改(您应该并且确实将其标记为const,因此它无法更改其值)。

I will try to explain 2 cycles here. 我将在这里尝试解释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>
    )
}

Here ( https://overreacted.io/a-complete-guide-to-useeffect/ ) is a very interesting article about the new useEffect Hook and some of the problems you encountered are addressed. 这里( https://overreacted.io/a-complete-guide-to-useeffect/ )是有关新useEffect Hook的非常有趣的文章,您遇到的一些问题已得到解决。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM