返回空数组的状态



我正在尝试从useState钩子访问状态,但即使我修改了它,它也给了我初始状态。

const quotesURL = "https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json";

function QuoteGenerator() {
const [quotes, setQuotes] = useState([]);
const [currentQuote, setCurrentQuote] = useState({ quote: "", author: "" });
useEffect(() => {
axios(quotesURL)
.then(result => {
console.log(result);
setQuotes(result.data);
})
.then(() => {
console.log(quotes);
});
}, []);

console.log(引号)返回空数组而不是对象数组

以下是您应该如何操作:

const quotesURL = "https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json";

function QuoteGenerator() {
const [quotes, setQuotes] = useState([]);
const [currentQuote, setCurrentQuote] = useState({ quote: "", author: "" });
useEffect(() => {         // THIS WILL RUN ONLY AFTER YOUR 1ST RENDER
axios(quotesURL)
.then(result => {
console.log(result);
setQuotes(result.data);  // HERE YOU SET quotes AND IT WILL TRIGGER A NEW RENDER
})
}, []);                 // BECAUSE YOU'VE SET IT WITH '[]'
useEffect(() => {         // THIS WILL RUN WHEN THERE'S A CHANGE IN 'quotes'
if (quotes.length) {
setSomeOtherState();   // YOU CAN USE IT TO SET SOME OTHER STATE
}
},[quotes]);
}

此代码的工作原理:

  • 第一次渲染:你只是初始状态。useEffects尚未运行。
  • 第一次渲染后:两种效果都将运行(按该顺序)。第一个将触发 axios 请求。第二个什么都不做,因为quotes还没有length
  • Axios 请求完成:then子句将运行,并将调用setQuotes来设置新的quotes值。这将触发重新渲染。
  • 第二次渲染:现在,quotes状态已使用新值更新
  • 第二次渲染后:只有第二个useEffect会运行,因为它正在"侦听"刚刚更改的quotes变量中的更改。然后你可以使用它来设置一些状态,就像你说的那样。

这是意料之中的。以下是代码的工作原理:

  1. quotessetQuotesuseState函数返回。
  2. useEffect挂载组件后首次运行。quotes(空数组)和setQuotes在此函数中可用。
  3. 当您的 axios 请求完成时,您setQuotes.但是,有两件事:1 - 这不会立即更新状态的值。2 - 在useEffect的上下文中,quotes仍然是一个空数组 - 当您执行setQuotes(result.data)时,您将创建一个新数组,并且在此上下文中无法直接访问该数组。
  4. 因此,console.log(quotes);将给出一个空数组。

取决于您尝试使用quotes的目的。为什么不直接与result.data合作?

更新:我正在考虑可能这样的事情:

function QuoteGenerator() {
const [quotes, setQuotes] = useState([]);
const [currentQuote, setCurrentQuote] = useState({ quote: "", author: "" });
useEffect(() => {
axios(quotesURL).then(result => {
console.log(result);
setQuotes(result.data);
setSomeOtherState(); // why not do it here?
});
}, []);
}

通过这种方式,您可以保持对数据的更严格控制,而无需将其交给生命周期方法。

重构代码以使其工作的另一种方法:

const quotesURL = "https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json";

function QuoteGenerator = ({ quote }) => {
const [quotes, setQuotes] = useState([]);
const [currentQuote, setCurrentQuote] = useState({ quote: "", author: "" });
const fetchQuote = async quote => {
const result = await axios.get(quotesURL);
setQuotes(result.data);
};
useEffect(() => {
fetchQuote(quote);
}, [quote]);
};

所以现在你的QuoteGenerator功能组件内部有一个名为fetchQuote的函数。useEffect钩子允许我们使用类似生命周期方法的东西,有点像将componentDidMountcomponentDidUpdate生命周期方法结合起来。在这种情况下,我调用了useEffect,其中包含一个函数,该函数将在每次此组件最初呈现到屏幕上以及每次组件更新时运行。

您可以在其他答案中看到,第二个参数作为空数组传递。我把quote作为该空数组中的第一个元素,因为它在我的示例中作为道具传递,但在其他人的示例中并非如此,因此它们有一个空数组。

如果你想理解为什么我们使用空数组作为第二个参数,我认为最好的解释方法是引用 Hooks API:

如果要运行效果并仅清理一次(在装载和卸载时),则可以传递空数组 ([]) 作为第二个参数。这告诉 React 你的效果不依赖于来自 props 或状态的任何值,所以它永远不需要重新运行。这不是作为特殊情况处理的 - 它直接遵循依赖关系数组始终的工作方式。

如果传递一个空数组 ([]),效果内部的 props 和状态将始终具有其初始值。虽然传递 [] 作为第二个参数更接近熟悉的组件 DidMount 和组件将卸载心智模型......

代替setState我们调用setQuotes,这用于更新报价列表,我传入了新的报价数组,该数组result.data

所以我传入了fetchQuote,然后传递了提供给quote组件的道具。

useEffect中空数组的第二个参数非常强大,并且不容易立即解释和/或理解每个人。例如,如果您执行类似useEffect(() => {})的操作,没有空数组作为第二个参数,则该函数useEffect将向 JSON 服务器终端节点或其他任何内容发出不间断的请求。

如果将useEffect(() => {}, [])与空数组一起使用,则只会调用一次,这与在基于类的组件中使用componentDidMount相同。

在我上面给出的示例中,我正在建立一个检查来限制调用useEffect的频率,我传入了道具的值。

我没有将异步函数放在useEffect中的原因是,我的理解是,如果我们传递异步函数或返回 Promise 的函数,至少根据我过去看到的错误,我们不能使用useEffect

话虽如此,该限制有一个解决方法,如下所示:

useEffect(
() => {
(async quote => {
const result = await axios.get(quotesURL);
setQuotes(result.data);
})(quote);
},
[quote]
);

这是一个更令人困惑的语法,但它应该有效,因为我们正在定义一个函数并立即调用它。类似于这样的东西:

(() => console.log('howdy'))()

相关内容

  • 没有找到相关文章