如何停止我的React组件重新渲染?它为下拉菜单中的每个对象重新渲染。

huangapple go评论74阅读模式
英文:

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

&lt;FormControl&gt;
  &lt;InputLabel&gt;Select a State&lt;/InputLabel&gt;
  &lt;Select value={location} onChange={selectionChangeHandler}&gt;
    {locations.map((value) =&gt; (
     &lt;MenuItem value={value.toLowerCase()} key={value.toLowerCase()} component={Link} to={`${value.toLowerCase()}/home`} &gt;
      {value}
     &lt;/MenuItem&gt; 
    ))}
  &lt;/Select&gt;
&lt;/FormControl&gt;

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) =&gt; {
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) =&gt; {
    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 = () =&gt; {
  const { location } = useParams();
  const [PageData, SetPageData] = useState();
  axios.get(`http://localhost:4000/${location}/home`).then((response) =&gt; {
    console.log(response.data);
    console.log(response.status);
    console.log(response.statusText);
    console.log(response.headers);
    console.log(response.config);
    SetPageData(response.data);
  });
  return &lt;h1&gt;This is my State Home Page Component for State {location}&lt;/h1&gt;;
};

You need to use this:

const StateHome = () =&gt; {
  console.log(&quot;StateHome&quot;);
  const { location } = useParams();
  const [PageData, SetPageData] = useState();

  useEffect(() =&gt; {
    axios.get(`http://localhost:4000/${location}/home`).then((response) =&gt; {
      console.log(response.data);
      console.log(response.status);
      console.log(response.statusText);
      console.log(response.headers);
      console.log(response.config);
      SetPageData(response.data);
    });
  }, []); // &lt;--- indicates &quot;on mount&quot;, loads once regadless of other side-effects (setState)
  
  return &lt;h1&gt;This is my State Home Page Component for State {location}&lt;/h1&gt;;
};

huangapple
  • 本文由 发表于 2023年2月6日 13:19:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/75357569.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定