为什么 setItems 函数(useState 挂钩)在 useEffect 的函数内部使用时有效,但直接在 useEffect 内部使用时无效?
Why does setItems function (useState hook) work when used inside a function inside useEffect but not when it is used inside useEffect directly?
在示例中,为什么 setItems
在这里起作用:
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";
export default function App() {
const [items, setItems] = useState([]);
useEffect(() => {
const fetchItems = async () => {
const result = await axios.get(
`https://www.breakingbadapi.com/api/characters`
);
setItems(result.data);
};
fetchItems();
}, []);
return (
<div>
{items.map(item => (
<div key={item.char_id}>{item.name}</div>
))}
</div>
);
}
https://codesandbox.io/s/boring-butterfly-2upbp
但不在此处(而是 returns 未定义 TypeError 项目):
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";
export default function App() {
const [items, setItems] = useState([]);
useEffect(() => {
const fetchItems = async () => {
const result = await axios.get(
`https://www.breakingbadapi.com/api/characters`
);
return result;
};
const result = fetchItems();
setItems(result.data);
}, []);
return (
<div>
{items.map(item => (
<div key={item.char_id}>{item.name}</div>
))}
</div>
);
}
您必须使用 then
函数来获取结果。
fetchItems().then(result => setItems(result.data))
您在 useEffect
挂钩中声明了一个异步函数,因此 fetchItems
将 return 一个承诺。但是由于 useEffect
函数参数不接受异步函数,所以最好在设置状态之前先解决承诺
const fetchItems = async () => {
const result = await axios.get(
`https://www.breakingbadapi.com/api/characters`
);
return result;
};
const result = fetchItems(); // result is a promise.
setItems(result.data);
在上面的代码片段中,fetchItems
是一个异步函数,所以它 returns 是一个承诺。因此,当您使用 result.data
时,您正在尝试访问 Promise 上的 data
,而不是解析后的值。
主要是因为fetchItems
return是一个承诺(async/await)。
但是还有另一个问题,因为您需要等待承诺得到解决,所以您需要将 await
添加到 fetchItems
但这无法完成,因为 useEffect
必须 return一个清理函数。
正确:
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";
export default function App() {
const [items, setItems] = useState([]);
// Also it's valid to create it directly inside the useEffect
const fetchItems = useCallback(async () => {
const result = await axios.get(
`https://www.breakingbadapi.com/api/characters`
);
setItems(result.data);
}, [setItems])
useEffect(() => {
fetchItems();
}, [fetchItems]);
return (
<div>
{items.map(item => (
<div key={item.char_id}>{item.name}</div>
))}
</div>
);
}
错误:
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";
export default function App() {
const [items, setItems] = useState([]);
// WRONG: useEffect is not a clean-up function.
useEffect(async () => {
const fetchItems = async () => {
const result = await axios.get(
`https://www.breakingbadapi.com/api/characters`
);
return result;
};
const result = await fetchItems();
setItems(result.data);
}, []);
return (
<div>
{items.map(item => (
<div key={item.char_id}>{item.name}</div>
))}
</div>
);
}
在示例中,为什么 setItems
在这里起作用:
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";
export default function App() {
const [items, setItems] = useState([]);
useEffect(() => {
const fetchItems = async () => {
const result = await axios.get(
`https://www.breakingbadapi.com/api/characters`
);
setItems(result.data);
};
fetchItems();
}, []);
return (
<div>
{items.map(item => (
<div key={item.char_id}>{item.name}</div>
))}
</div>
);
}
https://codesandbox.io/s/boring-butterfly-2upbp
但不在此处(而是 returns 未定义 TypeError 项目):
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";
export default function App() {
const [items, setItems] = useState([]);
useEffect(() => {
const fetchItems = async () => {
const result = await axios.get(
`https://www.breakingbadapi.com/api/characters`
);
return result;
};
const result = fetchItems();
setItems(result.data);
}, []);
return (
<div>
{items.map(item => (
<div key={item.char_id}>{item.name}</div>
))}
</div>
);
}
您必须使用 then
函数来获取结果。
fetchItems().then(result => setItems(result.data))
您在 useEffect
挂钩中声明了一个异步函数,因此 fetchItems
将 return 一个承诺。但是由于 useEffect
函数参数不接受异步函数,所以最好在设置状态之前先解决承诺
const fetchItems = async () => {
const result = await axios.get(
`https://www.breakingbadapi.com/api/characters`
);
return result;
};
const result = fetchItems(); // result is a promise.
setItems(result.data);
在上面的代码片段中,fetchItems
是一个异步函数,所以它 returns 是一个承诺。因此,当您使用 result.data
时,您正在尝试访问 Promise 上的 data
,而不是解析后的值。
主要是因为fetchItems
return是一个承诺(async/await)。
但是还有另一个问题,因为您需要等待承诺得到解决,所以您需要将 await
添加到 fetchItems
但这无法完成,因为 useEffect
必须 return一个清理函数。
正确:
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";
export default function App() {
const [items, setItems] = useState([]);
// Also it's valid to create it directly inside the useEffect
const fetchItems = useCallback(async () => {
const result = await axios.get(
`https://www.breakingbadapi.com/api/characters`
);
setItems(result.data);
}, [setItems])
useEffect(() => {
fetchItems();
}, [fetchItems]);
return (
<div>
{items.map(item => (
<div key={item.char_id}>{item.name}</div>
))}
</div>
);
}
错误:
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";
export default function App() {
const [items, setItems] = useState([]);
// WRONG: useEffect is not a clean-up function.
useEffect(async () => {
const fetchItems = async () => {
const result = await axios.get(
`https://www.breakingbadapi.com/api/characters`
);
return result;
};
const result = await fetchItems();
setItems(result.data);
}, []);
return (
<div>
{items.map(item => (
<div key={item.char_id}>{item.name}</div>
))}
</div>
);
}