簡體   English   中英

如何使用函數組件向 ref 公開函數?

[英]How can I expose functions to the ref using functional components?

我想創建一個組件,比如說一個日歷功能組件,它可以公開一些函數,如nextMonthprevMonth等。這樣使用它的父組件就可以使用ref訪問這些函數。 使用類組件很容易,因為實例方法是自動公開的。 如何使用功能組件實現相同的功能? 我知道我可以為此使用渲染道具模式。 但是還有其他解決方案嗎?

粗略的例子:

function Calendar() {
   const nextMonth = () => {...}
   const prevMonth = () => {...}

   return (
      <div>.....</div>
   )
}


function Parent() {
   const cal = createRef();

   const onNext = () => {
     cal.current.nextMonth();
   }

   return (
     <>
        <Calendar ref={cal} />
        <button onClick={onNext}>Next</button>
     </>
   )
}

您可以使用useImperativeHandle鈎子。

const Calendar = React.forwardRef((props, ref) => {
  const [month, setMonth] = useState(0)
  const nextMonth = () => { setMonth((prev) => prev + 1) }
  const prevMonth = () => { setMonth((prev) => prev - 1) }

  useImperativeHandle(ref, () => ({
    nextMonth,
    prevMonth
  }));

  return (
    <div>{month}</div>
  )
})

const Parent = () => {
  const cal = useRef()

  const onNext = () => {
    cal.current.nextMonth()
  }

  return (
    <React.Fragment>
      <Calendar ref={cal} />
      <button type="button" onClick={onNext}>Next</button>
    </React.Fragment>
  )
}

這是你可以做到的方法,即使它不是真正的 React 方式。 訣竅是在Calendar設置ref的當前值。

const Calendar = React.forwardRef((props, ref) => {
  const [month, setMonth] = useState(0)
  const nextMonth = () => { setMonth((prev) => prev + 1) }
  const prevMonth = () => { setMonth((prev) => prev - 1) }

  ref.current = { nextMonth, prevMonth } // eslint-disable-line

  return (
    <div>{month}</div>
  )
})

const Parent = () => {
  const cal = useRef()

  const onNext = () => {
    cal.current.nextMonth()
  }

  return (
    <React.Fragment>
      <Calendar ref={cal} />
      <button type="button" onClick={onNext}>Next</button>
    </React.Fragment>
  )
}

在功能組件中,您可以使用forwardRef將 ref 傳遞給子組件。

const Calendar = React.forwardRef((props, ref) => {
  const nextMonth = () => {...};
  const prevMonth = () => {...};

  return <div>.....</div>;
});

function Parent() {
  const cal = useRef(null);

  const onNext = () => {
    cal.current.nextMonth();
  };

  return (
    <>
      <Calendar ref={cal} />
      <button onClick={onNext}>Next</button>
    </>
  );
}

這項工作:

const Calendar = React.forwardRef((props, ref) => {
  const nextMonth = () => console.log("nextMonth");
  const prevMonth = () => console.log("prevMonth");
  ref.current = { nextMonth, prevMonth };
  return <div>.....</div>;
});

function Parent() {
  const cal = useRef(null);

  const onNext = () => {
    cal.current.nextMonth();
  };

  return (
    <>
      <Calendar ref={cal} />
      <button onClick={onNext}>Next</button>
    </>
  );
}

雖然@Matthieu Libeer 的答案是正確的,這應該對您有用,但您仍然可以考慮以 React 的方式進行。 到目前為止,您的Calendar是相同的不受控制的組件 通過 ref 訪問它的內部狀態(以及基於類的組件的方法),您將失去:

  1. 能夠進行預輸入驗證(例如,放棄每月第二個星期日的選擇)
  2. 以簡單的方式用不同的組件替換它

一旦它成為完全可控的組件+與道具名稱中的本機控件保持一致,你會得到類似的東西

<Calendar value={currentData} onChange={this.validateAndSetDate} />

通過這種方式,它可以很容易地替換為兼容的組件(比如<input type="date" /> )並且驗證更容易。 你仍然可能需要forwardRef命令性地對.focus()說,但其他方面的痛苦會更少。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM