Parent state getting reset back to initial value after different child is clicked.

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

Parent state getting reset back to initial value after different child is clicked

问题

我有一个父组件和子组件。每当子组件中的链接被点击时,我想执行作为props传递的父组件的点击处理程序。在点击处理程序中,我只想在父组件中递增一个整数状态。

问题是:每次点击单个链接(子组件)时,numCars状态都会正确递增。例如,如果我点击“car1”链接5次,numCars状态将增加到5。然而,如果我然后点击“car2”,numCars状态会重置为0。如果我继续点击“car2”,numCars将递增正常,直到我点击另一辆车。就像每个子组件都有自己的父组件一样。

为什么会发生这种情况?

export default function Garage() {
   const [numCars, setNumCars] = useState(0);

   const carHandleClick = (carName) => {
      console.log("Clicked by " + carName); 
      setNumCars(numCars + 1);
   } 

   const cars = [
      {
         name: "car1"
      },
      {
         name: "car2"
      },
      {
         name: "car3"
      }
   ]

   return (
      <ul>
         {cars.map((car) =>
            <Car name={car.name} carHandleClick={carHandleClick}/>   
         )}
      <ul>
   );
}

export default function Car( {name, carHandleClick} ) {
   return (
      <li>
         <Link to=... onClick={() => carHandleClick(name)}>
            {name}
         </Link>
      </li>
   )
}
英文:

I have a parent and child components. Whenever the Link in the child component is clicked, I want to execute the parent's click handler that is passed in as props. In the click handler, I simply want to increment an integer state in the parent component.

The issue: the numCars state is correctly incremented for each single Link (child component) I click. For instance, if I click on the Link "car1" 5 times, the numCars state is incremented to 5. However, if I then click on "car2", the numCars state is reset back to 0. If I continue clicking "car2", numCars is incremented properly, until I click on another car. It's as if each child has its own parent component.

Why is this happening?

export default function Garage() {
   const [numCars, setNumCars] = useState(0);

   const carHandleClick = (carName) =&gt; {
      console.log(&quot;Clicked by &quot; + carName); 
      setNumCars(numCars + 1);
   } 

   const cars = [
      {
         name: &quot;car1&quot;
      },
      {
         name: &quot;car2&quot;
      },
      {
         name: &quot;car3&quot;
      }
   ]

   return (
      &lt;ul&gt;
         {cars.map((car) =&gt;
            &lt;Car name={car.name} carHandleClick={carHandleClick}/&gt;   
         }
      &lt;ul&gt;
   );
}

export default function Car( {name, carHandleClick} ) {
   return (
      &lt;li&gt;
         &lt;Link to=... onClick={() =&gt; carHandleClick(name)}
            {name}
         &lt;/Link&gt;
      &lt;/li&gt;
   )
}

答案1

得分: 1

carHandleClick = (carName) => {
  setNumCars(prev => prev + 1);
}

或者使用带有 [numCars]useCallback 钩子:

carHandleClick = useCallback((carName) => {
  setNumCars(numCars + 1);
}, [numCars]);

更新:
问题与导航链接导致父组件卸载和重新挂载,因此其状态被重置有关。

处理此问题的一种方法是在顶层使用上下文:

export const MyContext = createContext();

const App = () => {
  const [numCars, setNumCars] = useState(0);
  const carHandleClick = (carName) => {
    console.log("Clicked by " + carName);
    setNumCars((prev) => prev + 1);
  };

  return (
    <MyContext.Provider value={{ numCars, carHandleClick }}>
      //...
    </MyContext.Provider>
  );
}

现在您只需从父组件和子组件中使用它:

import { MyContext } from "./App";

export default function Garage() {
  const { carHandleClick, numCars } = useContext(MyContext);

  //...
  return (
    <ul>
      {cars.map((car) => (
        <Car name={car.name} />
      ))}
    </ul>
  );
}
import { MyContext } from "./App";

function Car({ name }) {
  const { carHandleClick, numCars } = useContext(MyContext);
  //...
  return (
    <li>
      <Link onClick={() => carHandleClick(name)}>{name}</Link>
    </li>
  );
}

了解更多关于 useContext 的信息。

英文:
carHandleClick = (carName) =&gt; {
 setNumCars(prev =&gt; prev + 1);
} 

you want always to use the functional form of the state setter if you want to update it based on its previous value

or a useCallback hook with [numCars]:

carHandleClick = useCallback((carName) =&gt; {
setNumCars(numCars + 1);
},[numCars])

Update:
the issue was related to the fact navigate with the link unmounts and remounts the parent component so its state is reset.<br>
one way to handle this is to use a context in the top level:<br>

export const MyContext = createContext();

const App = () =&gt; {
  const [numCars, setNumCars] = useState(0);
  const carHandleClick = (carName) =&gt; {
    console.log(&quot;Clicked by &quot; + carName);
    setNumCars((prev) =&gt; prev + 1);
  };

  return (
    &lt;MyContext.Provider value={{ numCars, carHandleClick }}&gt;
      //...
    &lt;/MyContext.Provider&gt;
  );
}

now you juste consume it from both parent and child:

import { MyContext } from &quot;./App&quot;;

export default function Garage() {
  const { carHandleClick, numCars } = useContext(MyContext);

  //...
  return (
    &lt;ul&gt;
      {cars.map((car) =&gt; (
        &lt;Car name={car.name} /&gt;
      ))}
    &lt;/ul&gt;
  );
}
import { MyContext } from &quot;./App&quot;;

function Car({ name }) {
  const { carHandleClick, numCars } = useContext(MyContext);
  //...
  return (
    &lt;li&gt;
      &lt;Link onClick={() =&gt; carHandleClick(name)}&gt;{name}&lt;/Link&gt;
    &lt;/li&gt;
  );
}

Learn more about useContext

huangapple
  • 本文由 发表于 2023年6月30日 02:08:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76583607.html
匿名

发表评论

匿名网友

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

确定