英文:
How do I stop the re-rendering of my react component? It rerenders for every object in a drop down
问题
在构建我的网站主页后,我终于弄清楚了如何动态导航到其他页面。当用户单击下拉菜单并选择一个州时,我希望浏览器呈现该州的主页。导航是有效的,但会重新渲染组件50次,这点我不理解。我怀疑是由于创建菜单项的map函数导致的。我可以构建50个单独的菜单项,但这太丑陋了。
我刚开始学习React。我在后端开发方面有7年的经验,但我仍在努力掌握React开发。我创建了一个使用Material UI的网页,其中有一个下拉菜单,看起来像这样:
<FormControl>
<InputLabel>Select a State</InputLabel>
<Select value={location} onChange={selectionChangeHandler}>
{locations.map((value) => (
<MenuItem value={value.toLowerCase()} key={value.toLowerCase()} component={Link} to={`${value.toLowerCase()}/home`}>
{value}
</MenuItem>
))}
</Select>
</FormControl>
这将返回一个包含50个州的下拉菜单。当用户单击一个州时,我希望程序在单击时路由到该页面。这种动态路由有效,但会重新渲染我的组件50次。我认为这是因为下拉菜单是在.map函数内构建的,而该列表中有50个条目。
我可以删除map函数并硬编码50个菜单项,但这太丑陋了。
以下是我的onChange函数:
const selectionChangeHandler = (event) => {
console.log(event.target.value);
}
我还尝试删除component={Link},并在selectionChangeHandler中使用useNavigate钩子,如下所示:
const selectionChangeHandler = (event) => {
console.log(event.target.value);
setlocation(event.target.value);
const link = `${event.target.value}/home`;
navigate(link);
}
这个方法也有效,但同样会重新渲染50次。我感到困惑。
我将上述问题发布到Reddit,然后进行了一些研究。事实证明,在React中,当更新父组件的状态时,会重新渲染所有子组件。这可能是问题的原因,但我不知道如何解决它。即使将状态作为prop传递给子组件,我仍然需要链接到正确的页面。
我有点紧张发帖,我真的尽力在寻求帮助之前解决自己的问题,而且随着学习的深入,我可能会频繁寻求帮助。我致力于学习,但有些问题我无法独自解决。
英文:
After building the homepage of my website I finally figured out how to dynamically navigate to other pages. I wanted the browser to render the State homepage when a user clicked on a dropdown and selected a state. The navigation works, but it re-renders the component 50 times which I do not understand. I suspect it is due to the map function that is creating the menuitems. I could build out 50 individual menuitems but that is really ugly.
I am just starting out learning React. I have 7 YRS experience in backend development, but I am still trying to get a handle on React development. I have created a wepage with Material UI that has a dropdown that looks like this
<FormControl>
<InputLabel>Select a State</InputLabel>
<Select value={location} onChange={selectionChangeHandler}>
{locations.map((value) => (
<MenuItem value={value.toLowerCase()} key={value.toLowerCase()} component={Link} to={`${value.toLowerCase()}/home`} >
{value}
</MenuItem>
))}
</Select>
</FormControl>
This returns a dropdown with the 50 states in it. When the user clicks on a state I want the program to route to that page on click. This dynamic routing works BUT. It re-renders my component 50 times. I think this is happening because the dropdown is being built inside of a .map functions and there are 50 entries in that list.
I can remove the map function and hardcode in 50 menuitems but that is ugly.
Here is my onChange Function
const selectionChangeHandler = (event) => {
console.log(event.target.value)
}
I have also tried removing the component={Link} and using the useNavigate hook in the selectionChangeHandler like so
const selectionChangeHandler = (event) => {
console.log(event.target.value)
setlocation(event.target.value)
link = `${event.target.value}/home`
navigate(link)
}
This works but also renders 50 times. I am at a loss.
I cross posted the above to reddit and then I researched a little more. It turns out in React. When a parent component's state is updated it re-renders all child components. This may be what is going on here, but I do not know how to fix it. Even if I pass the state as a prop to the child component I still have to link to the correct page.
I am kind of nervous about posting I really tried to put work into solving my own problem before reaching out for help, and I might be reaching out for help a lot as I learn. I am committed to learning, but some problems I just cannot figure out on my own.
Link to Code Link to Code
答案1
得分: 1
问题出在StateHome.js
文件内。你在组件中直接使用了一个裸露的axios.get
调用,所以每当组件因状态变化而重新渲染时,它都会重新执行。
当你获得结果后,你在同一组件内设置了状态,这将导致组件重新渲染,然后再次运行axios.get
调用,从而导致循环。
我理解你想要在有人访问/alabama/home
页面时调用该端点。要告诉React
“在组件加载时执行一次”,你必须使用useEffect
并带有一个空的依赖数组。所以,不要使用这个:
const StateHome = () => {
const { location } = useParams();
const [PageData, SetPageData] = useState();
axios.get(`http://localhost:4000/${location}/home`).then((response) => {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
SetPageData(response.data);
});
return <h1>This is my State Home Page Component for State {location}</h1>;
};
你需要使用这个:
const StateHome = () => {
console.log("StateHome");
const { location } = useParams();
const [PageData, SetPageData] = useState();
useEffect(() => {
axios.get(`http://localhost:4000/${location}/home`).then((response) => {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
SetPageData(response.data);
});
}, []); // <--- 表示“在挂载时”只加载一次,不受其他副作用的影响(setState)
return <h1>This is my State Home Page Component for State {location}</h1>;
};
英文:
The problem here is inside StateHome.js
. You use a naked axios.get
call directly in your component so it's going to re-render anytime the component changes from state change.
When you get the results you set state inside the same component which re-renders the component, which then re-runs the axios.get call, causing the loop.
I understand you want to call that endpoint when someone lands on the /alabama/home
page. To tell React
"Do this one time when the component loads" you must use a useEffect
with an empty dependency array. So instead of this:
const StateHome = () => {
const { location } = useParams();
const [PageData, SetPageData] = useState();
axios.get(`http://localhost:4000/${location}/home`).then((response) => {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
SetPageData(response.data);
});
return <h1>This is my State Home Page Component for State {location}</h1>;
};
You need to use this:
const StateHome = () => {
console.log("StateHome");
const { location } = useParams();
const [PageData, SetPageData] = useState();
useEffect(() => {
axios.get(`http://localhost:4000/${location}/home`).then((response) => {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
SetPageData(response.data);
});
}, []); // <--- indicates "on mount", loads once regadless of other side-effects (setState)
return <h1>This is my State Home Page Component for State {location}</h1>;
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论