为什么不再使用 Effect 运行 my API 获取并将结果保存到状态?
Why won't useEffect run my API fetch anymore and save results to state?
目标:
请注意,使用的示例并非我项目的确切上下文,但非常相似,因此为此进行了简化post
我正在尝试使用 WP-API 来使用 Wordpress 类别、post 标题和 post 内容来生成动态 React 应用程序。
每条信息都在 React 应用程序的生成中发挥作用:
Wordpress 类别用于填充 React App 中的侧边栏导航组件。每个 Wordpress 类别将充当此导航中的一个项目。将此组件视为内容的 table。
post 标题将是每个类别的子菜单项。因此,以食谱为例,如果菜单上的类别项目之一是“墨西哥食品”,post 标题或子菜单项目可能是“炸玉米饼”、“辣酱玉米饼馅”、“玉米粉蒸肉”。
以墨西哥食物为例,post 内容将根据您单击的子菜单项显示在主内容区域中。因此,如果您单击侧边栏菜单组件中的“Tacos”,主要内容将填充“Tacos”的食谱。这个主要内容区域是它自己的独立组件。
问题:
主要问题是我能够使用 React hooks、useEffect 和 fetch 毫无问题地获取要填充在侧边栏导航组件上的项目。但是,一旦我单击子菜单项,食谱将不会填充到主要内容区域。
研究结果:
我能够确定 useEffect 以某种方式没有设置我的状态。我声明了两个变量,它们处理通过获取 WP-API 获得的 JSON 数据。然后我想使用 setPost 函数将结果设置到我的组件状态中。但是,此 setPost 函数不设置状态。为了清楚起见,下面我将 post 代码示例。
代码:
这是我当前的主要内容组件,它接收道具。具体来说,它从 React Router 接收 'match' 道具,其中包含特定 WordPress post 的 URL slug。我用这个
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"
}
我的第 3 个控制台日志的结果 console.log(postContent[0])
生成了一个 object,其中 returns 该特定 post 的每个细节都是正确的。
之后,我使用setPost(postContent[0])
将此信息保存到我的post
状态。
为了证实这一点,我运行console.log(post)
,它returns一个简单的[]
,一个空数组。
结果与预期:
我期望 setPost(postContent[0])
中的内容会以 post
状态正确保存,以便我可以使用该内容在页面上呈现内容。
然而,实际结果是没有任何内容保存到状态,每当我点击其他类别,例如“玉米粉蒸肉”或“辣酱玉米饼馅”时,URL 确实会更新,但它第一次获取后不再获取信息。
我知道这是一个冗长的问题,但任何能帮助这个可怜的新手的人都是绝对的救星!提前致谢!
setPost
和组件 class 的正常 setState
一样也是异步的。
所以你应该使用
await setPost(postContent[0])
console.log(post)
在函数中获取结果
也许尝试将 const postContent = await fetchedPost.json()
更改为 const postContent = await fetchedPost.data
首先让我们看看你的第二个problem/expectation:它从不在第一次获取后获取信息。
useEffect 函数可能有两个参数。回调函数和依赖项数组。 effect 函数只会在其依赖项之一发生更改时被调用。如果省略第二个参数,函数将在每个 re-render 上 运行。
你的数组是空的;这意味着当组件首次安装时效果将 运行 ,之后它不会 re-run.
要解决该问题,您需要正确添加依赖项。
在您的情况下,如果 props.match.params.wpslug 发生变化,您希望 re-fetch。
useEffect(() => {
fetchPost()
}, [props.match.params.wpslug])
现在针对貌似没有正确设置状态的问题。
setting/updating 您的示例中的状态似乎没有任何问题。
问题是 'post' 变量是针对当前的 render-cycle 已经设置为 [] 并且在下一个周期之前不会更改(您应该并且确实将其标记为 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 的非常有趣的文章,解决了您遇到的一些问题。
目标:
请注意,使用的示例并非我项目的确切上下文,但非常相似,因此为此进行了简化post
我正在尝试使用 WP-API 来使用 Wordpress 类别、post 标题和 post 内容来生成动态 React 应用程序。
每条信息都在 React 应用程序的生成中发挥作用:
Wordpress 类别用于填充 React App 中的侧边栏导航组件。每个 Wordpress 类别将充当此导航中的一个项目。将此组件视为内容的 table。
post 标题将是每个类别的子菜单项。因此,以食谱为例,如果菜单上的类别项目之一是“墨西哥食品”,post 标题或子菜单项目可能是“炸玉米饼”、“辣酱玉米饼馅”、“玉米粉蒸肉”。
以墨西哥食物为例,post 内容将根据您单击的子菜单项显示在主内容区域中。因此,如果您单击侧边栏菜单组件中的“Tacos”,主要内容将填充“Tacos”的食谱。这个主要内容区域是它自己的独立组件。
问题:
主要问题是我能够使用 React hooks、useEffect 和 fetch 毫无问题地获取要填充在侧边栏导航组件上的项目。但是,一旦我单击子菜单项,食谱将不会填充到主要内容区域。
研究结果:
我能够确定 useEffect 以某种方式没有设置我的状态。我声明了两个变量,它们处理通过获取 WP-API 获得的 JSON 数据。然后我想使用 setPost 函数将结果设置到我的组件状态中。但是,此 setPost 函数不设置状态。为了清楚起见,下面我将 post 代码示例。
代码:
这是我当前的主要内容组件,它接收道具。具体来说,它从 React Router 接收 'match' 道具,其中包含特定 WordPress post 的 URL slug。我用这个
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"
}
我的第 3 个控制台日志的结果 console.log(postContent[0])
生成了一个 object,其中 returns 该特定 post 的每个细节都是正确的。
之后,我使用setPost(postContent[0])
将此信息保存到我的post
状态。
为了证实这一点,我运行console.log(post)
,它returns一个简单的[]
,一个空数组。
结果与预期:
我期望 setPost(postContent[0])
中的内容会以 post
状态正确保存,以便我可以使用该内容在页面上呈现内容。
然而,实际结果是没有任何内容保存到状态,每当我点击其他类别,例如“玉米粉蒸肉”或“辣酱玉米饼馅”时,URL 确实会更新,但它第一次获取后不再获取信息。
我知道这是一个冗长的问题,但任何能帮助这个可怜的新手的人都是绝对的救星!提前致谢!
setPost
和组件 class 的正常 setState
一样也是异步的。
所以你应该使用
await setPost(postContent[0])
console.log(post)
在函数中获取结果
也许尝试将 const postContent = await fetchedPost.json()
更改为 const postContent = await fetchedPost.data
首先让我们看看你的第二个problem/expectation:它从不在第一次获取后获取信息。
useEffect 函数可能有两个参数。回调函数和依赖项数组。 effect 函数只会在其依赖项之一发生更改时被调用。如果省略第二个参数,函数将在每个 re-render 上 运行。 你的数组是空的;这意味着当组件首次安装时效果将 运行 ,之后它不会 re-run.
要解决该问题,您需要正确添加依赖项。 在您的情况下,如果 props.match.params.wpslug 发生变化,您希望 re-fetch。
useEffect(() => {
fetchPost()
}, [props.match.params.wpslug])
现在针对貌似没有正确设置状态的问题。 setting/updating 您的示例中的状态似乎没有任何问题。 问题是 'post' 变量是针对当前的 render-cycle 已经设置为 [] 并且在下一个周期之前不会更改(您应该并且确实将其标记为 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 的非常有趣的文章,解决了您遇到的一些问题。