如何將一個按鈕設定為控制所有手風琴的開關?
P粉391677921
P粉391677921 2023-08-30 16:57:51
0
2
655
<p>我有一個組件,使用以下程式碼創建一個可折疊的手風琴:</p> <pre class="brush:php;toolbar:false;">import React, {useState} from 'react'; const Collapsible = (props) =>{ const [open, setOpen] = useState(false); const toggle = () => { setOpen(!open); } return( <div> <button className={props.level} onClick={toggle}>{props.label}</button> {open && ( <div className="toggle"> {props.children} </div> )} </div> ) } export default Collapsible;</pre> <p>我在主應用程式的多個位置使用它,有時在其他手風琴中使用手風琴。在多個實例中,我實際上不知道頁面上會有多少手風琴,因為它們是基於資料動態渲染的。考慮到這一點,我想在主應用程式中創建一個按鈕,打開(和關閉)所有手風琴,而不需要設置一個固定的數量,並且不需要在主應用程式中渲染所有手風琴(即一些手風琴在其他元件中渲染,然後匯入主應用程式)。 </p> <p>我嘗試使用ref hooks來實現這一點:</p> <ol> <li>在Collapsible組件的按鈕中加入ref,並透過props從父組件存取:</li> </ol> <pre class="brush:php;toolbar:false;"><button className={props.level} onClick={toggle} ref={props.innerRef}>{props.label}</button> ;</pre> <ol start="2"> <li>在主應用程式中加入以下ref:</li> </ol> <pre class="brush:php;toolbar:false;">const childRef = useRef(); const openClick = () => { childRef.state = true; } const closeClick = () => { childRef.state = false; }</pre> <ol start="3"> <li>在主應用程式中使用以下按鈕:</li> </ol> <pre class="brush:php;toolbar:false;"><button onClick = {openClick}> 展開全部 </button> <button onClick = {closeClick}> 折疊全部 </button></pre> <ol start="4"> <li>在渲染時將ref加入手風琴:</li> </ol> <pre class="brush:php;toolbar:false;"><Collapsible label="" level="content" innerRef={childRef}></pre> <p>這實際上什麼都沒做,可能是因為我在第2步中嘗試訪問狀態的方式是錯誤的,但我認為這是值得一試的...</p> <p>對於是否可行的任何想法嗎? </p>
P粉391677921
P粉391677921

全部回覆(2)
P粉441076405

您可以使用Redux

  1. 當您渲染手風琴時,請給它們一個特定的id並將其保存在儲存中。
  2. 建立一個切片openAllAccordions,循環遍歷ID,並將屬於該ID的手風琴設定為open=true
  3. 建立一個切片closeAllAccordions,循環遍歷ID,並將屬於該ID的手風琴設定為open=false
P粉809110129

在一個更或多或少任意的元件實例集合中,需要一些協調是很常見的。我成功使用的一種方法是建立一個與關聯鉤子的Context,元件可以使用該鉤子進行註冊。此鉤子傳回共享狀態的視圖和修改該狀態的函數,以滿足您的需求。

在這裡,您可以建立一個儲存每個已註冊元件的opener函數並提供openAll/closeAll函數的Context:

const AccordionProvider = ({ children }) => {
  const [openers] = useState(new Set());

  // 当创建时,是否应该展开新的可折叠项?
  //(支持递归展开是必要的)
  const [defaultOpen, setDefaultOpen] = useState(false);

  const register = useCallback(
    (opener) => {
      openers.add(opener);
      return () => openers.delete(opener); // 返回一个用于`useEffect`的取消注册函数
    },
    [openers]
  );

  const openAll  = useCallback(() => {
    setDefaultOpen(true);
    openers.forEach(opener => opener(true)),
  }, [setDefaultOpen, openers]);

  const closeAll = useCallback(() => {
    setDefaultOpen(false);
    openers.forEach(opener => opener(false)),
  }, [setDefaultOpen, openers]);

  return (
    <AccordionContext.Provider
      value={{ register, openAll, closeAll, defaultOpen }}
      children={children}
    />
  );
};

...還有一個被每個子元件呼叫的鉤子,用於在上下文中註冊,並傳回熟悉的toggle/open值:

const useAccordionAsClient = () => {
  const { register, defaultOpen } = useContext(AccordionContext);

  const [open, opener] = useState(defaultOpen);
  const toggle = useCallback(() => opener((open) => !open), [opener]);

  useEffect(() => register(opener), [register, opener]);

  return { toggle, open };
};

還有一個用於執行批次操作的獨立鉤子也很方便:

const useAccordionAsManager = () => {
  const { openAll, closeAll } = useContext(AccordionContext);

  return { openAll, closeAll };
};

Sandbox

#請注意,為簡單起見,這裡只是使用了單獨的opener(又稱setOpen)函數作為每個已註冊元件的唯一識別碼。一個靈活的替代方案是使用其他標識符,這樣您可以在導航等情況下打開/關閉任意的手風琴。

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板