我正在创建我的第一个自制的Web开发项目,并且遇到了无限循环。完整项目可在https://github.com/Olks95/my-dnd/tree/spellbook上找到。所以问题是:是什么原因导致了循环,我该如何解决?
(调用ContentSelector-Spellbook时,循环会在“游乐场”组件的第二项中的某处发生。自定义钩子useHandbook在Spellbook中被调用并连续调用API,显然应该只发生一次...刷新或单击返回以停止垃圾邮件)
据我所知,这个问题不在自定义钩子本身中,因为我已经进行了多次尝试来重写它,并且在useEffect()的末尾添加了一个空的依赖项数组。我将在此处尝试使用示例代码进行解释。
import { Component1, Component2, Component3 } from './ContentSelector.js';
const components = {
option1: Component1,
option2: Component2
option3: Component3
}
const Playground = (props) => {
const LeftItem = components['option1']
const MiddleItem = components['option2']
const RightItem = components['option3']
...
}
我希望能够选择在每个元素中放置什么内容,并最终制作一个ContentSelector组件,该组件将所有内容组件都放在一个文件中,并分别导入/导出。这似乎是一种奇怪的方法,但这是我发现使其起作用的唯一方法。 (是否可能是导致循环的原因?)由于在开发中还处于初期阶段,因此对选择进行了硬编码。 item变量以大写字母开头,因此以后我可以将它们作为组件渲染,如下所示:
<LeftItem ...some properties... />
游乐场然后返回以下内容进行渲染:
return(
<React.Fragment>
<div className="container">
<div className="flex-item">
/* Working select-option to pass correct props to Component1 */
<div className="content">
<LeftItem ...some properties... />
</div>
</div
<div className="flex-item">
/* Currently the same selector that changes the content of the LeftItem */
<div className="content">
<MiddleItem ...some properties... />
</div>
</div>
/*RightItem follows the same formula but currently only renders "coming soon..." */
</div>
</React.Fragment>
)
然后,内容选择器具有三个组成部分:
Component1:调用仅运行一次的自定义钩子。然后将信息发送到另一个组件进行渲染。一切正常。
Component2:无限次调用自定义钩子,但预期其工作方式与组件1相同...
Component3:渲染即将推出...
请参阅下面的组件1和2:
export const Component1 = (props) => {
const [ isLoading, fetchedData ] = useDicecloud(props.selectedChar);
let loadedCharacter = null;
if(fetchedData) {
loadedCharacter = {
name: fetchedData[0].Name,
alignment: fetchedData[0].Alignment,
/* a few more assignments */
};
}
let content = <p>Loading characters...</p>;
if(!isLoading && fetchedData && fetchedData.length > 0) {
content = (
<React.Fragment>
<Character
name={loadedCharacter.name}
alignment={loadedCharacter.alignment}
/* a few more props */ />
</React.Fragment>
)
}
return content;
}
export const Component2 = (props) => {
const [ fetchedData, error, isLoading ] = useHandbook('https://cors-anywhere.herokuapp.com/http://dnd5eapi.co/api/spells/?name=Aid')
let content = <p>Loading spells...</p>;
if(!isLoading && fetchedData) {
/* useHandbook used to return text to user in a string in some situations */
if(typeof fetchedData === 'string') {
content = (
<React.Fragment>
<p> {fetchedData} </p>
</React.Fragment>
)
} else {
content = (
<React.Fragment>
<Spellbook
/* the component that will in the future render the data from the API called in useHandbook */
/>
</React.Fragment>
)
}
}
return content;
}
我已经在这个问题上工作了几天,随着我的前进,它变得越来越混乱。我希望该错误出现在useHandbook中,但经过多次重制后,似乎并非如此。当前的useHandbook非常简单,如下所示。
export const useHandbook = (url) => {
const [ isLoading, setIsLoading ] = useState(false);
const [ error, setError ] = useState(null);
const [ data, setData ] = useState(null);
const fetchData = async () => {
setIsLoading(true);
try {
const res = await fetch(url, {
method: "GET",
mode: 'cors'
});
const json = await res.json();
setData(json);
setIsLoading(false);
} catch(error) {
setError(error);
}
};
useEffect(() => {
fetchData();
}, []); //From what the documentation says, this [] should stop it from running more than once.
return [ data, error, isLoading ];
};
编辑:我运行了带有react扩展的chrome开发人员工具,并看到了一些有用的东西:
Image showing Component2 (Spellbook) run inside itself infinite times
答案 0 :(得分:0)
您可以修改自定义挂钩useHandbook's
useEffect
挂钩,以将URL作为依赖项,因为useEffect
与componentWillMount
,componentDidUpdate
和{{1 }},您的情况是多次componentWillUnmount
。所以你可以做的。
componentDidUpdate
因为除非URL发生更改,否则无需重新获取数据
答案 1 :(得分:0)
我发现了错误。 Component2
的真实名称是Spellbook
,我也称其为尚未制作的渲染组件。事实证明,我是从内部调用该组件的。
易于在问题的编辑部分的图像中看到。