reactjs - Hur man ställer in standardtillstånd för React toggle-anpassad hook?


Så scenariot är att när jag klickar på en chevron-knapp, öppnas en ackordionkomponent som är placerad precis under chevron-knappen och visar sina barnkomponenter.

Jag vill däremot inte att andra chevron-knappar ska dela samma tillstånd så att endast en klickad chevron-knapp med ett relaterat dragspel expanderar.

Och som standard, när mallkomponenten just har monterats, expanderar accordions och visar sina barn med chevron-knappar som pekar upp ^

koder :

// useChevron hook

import { useState } from 'react';


const useChevron = () => {
  const [isChevronUp, setIsChevronUp] = useState<Partial<any>>({});


  const handleChevron = (id: string) => {
    setIsChevronUp((previousState) => ({
      ...previousState,
      [id]: !previousState[id],
    }));
  };

  return { isChevronUp, setIsChevronUp, handleChevron };
};

export default useChevron;

// template
...
const { handleChevron, isChevronUp } = useChevron();
...

<div id="containerOne">

// when it has just been rendered isChevronUp is empty object so in case set isOpen as true which makes chevron looks like ^ and shows accordion's children
<ChevronButton
            isOpen={_.isEmpty(isChevronUp) ? true : !!isChevronUp.containerOne} 
            id='containerOne'
            onClick={() => handleChevron('containerOne')}
          />
</div>
<Accordion isOpen={_.isEmpty(isChevronUp) ? true : !!isChevronUp.containerOne}>
<ChildrenComponent1 />
<ChildrenComponent2 />
...

Det verkar fungera förutom att jag måste klicka två gånger på chevron-knappen första gången, sedan fungerar växlingen som förväntat.

Jag försökte nedan:

const [isChevronUp, setIsChevronUp] = useState<Partial<SomeType>>({
      'default': true
});
...

<ChevronButton
            isOpen={Object.keys(isChevronUp).length === 1 ? isChevronUp.default : !!isChevronUp.containerOne} 
            id='containerOne'
            onClick={() => handleChevron('containerOne')}
          />
</div>
<Accordion isOpen={Object.keys(isChevronUp).length === 1 ? isChevronUp.default : !!isChevronUp.containerOne}>

men det är samma sak att behöva klicka på pilknappen två gånger.

Vad är det bästa sättet att ställa in standard för chevron upp och att accordion är expanderad i denna situation och lösa problemet med att klicka två gånger?

Tack i förväg.

Svar #1

Du kan lägga till en initialiseringsfunktion för chevrons-hooken, där du skapar ett fält med en nyckel som är lika med chevron-id och ett värde som är sant som standard. Sedan kan du bara hämta chevron-värdet utan ett villkor.

// useChevron hook

import { useState } from 'react';

const useChevron = () => {
  const [isChevronUp, setIsChevronUp, initChevron] = useState<Partial<any>>({});

  const init = (id: string) => {
    setIsChevronUp((previousState) => ({
      ...previousState,
      [id]: true,
    }));
  };

  const handleChevron = (id: string) => {
    setIsChevronUp((previousState) => ({
      ...previousState,
      [id]: !previousState[id],
    }));
  };

  return { isChevronUp, setIsChevronUp, handleChevron, init };
};

export default useChevron;

// template
...
const { handleChevron, isChevronUp, init } = useChevron();

useEffect(() => {
  init('containerOne');
}, []);
...

<div id="containerOne">

// when it has just been rendered isChevronUp is empty object so in case set isOpen as true which makes chevron looks like ^ and shows accordion's children
<ChevronButton
            isOpen={isChevronUp.containerOne} 
            id='containerOne'
            onClick={() => handleChevron('containerOne')}
          />
</div>
<Accordion isOpen={isChevronUp.containerOne}>
<ChildrenComponent1 />
<ChildrenComponent2 />
...

Svar #2

Ditt problem är ditt isChevronUp-tillståndshookvärde, det anger inte om den angivna chevronen är vald utan innehåller ett objekt med de valda chevronerna.

Som sådan bör isChevronUp vara en funktion som du anropar, eller så bör du kontrollera tillståndet därefter med hjälp av id-strängen för din chevron

// useChevron hook

import { useState } from 'react';


const useChevron = () => {
  const [chevronState, setChevronState] = useState<Partial<any>>({});


  const handleChevron = (id: string) => {
    setChevronState((previousState) => ({
      ...previousState,
      [id]: !previousState[id],
    }));
  };

  const isChevronUp = (id: string) => Boolean(chevronState[id]);

  return { isChevronUp, handleChevron };
};

export default useChevron;

Och när du kontrollerar om det är öppet, gör:

<ChevronButton
  isOpen={isChevronUp('containerOne')}
...

något sådant