如何使用功能组件向ref公开功能?

时间:2019-08-03 09:43:04

标签: reactjs react-native

我想创建一个组件,可以说一个日历功能组件,它可以公开某些功能,例如nextMonthprevMonth等。这样,使用它的父组件可以使用{{ 1}}。使用类组件很容易,因为实例方法是自动公开的。如何通过功能组件实现相同的目的?我知道我可以为此使用渲染道具模式。但是还有其他解决方案吗?

一个粗略的例子:

ref

4 个答案:

答案 0 :(得分:5)

您可以使用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>
  )
}

答案 1 :(得分:3)

即使不是真正的React方法,也可以在这里进行操作。 技巧是在ref中设置Calendar的当前值。

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>
  )
}

答案 2 :(得分:0)

在功能组件中,您可以使用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>
    </>
  );
}

答案 3 :(得分:0)

虽然@Matthieu Libeer的答案是正确的,并且这应该对您有用,但仍应考虑以React方式进行。现在,您的Calendar是相同的uncontrolled component。通过ref访问其内部状态(以及在基于类的组件的情况下的方法),您正在失去:

  1. 能够进行预输入验证(例如,放弃每月第二个星期日的选择)
  2. 以简单的方式将其替换为不同的组件

一旦它是完全可控的组件+与道具名称中的本机控件保持一致,您将得到类似的东西

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

通过这种方式,可以轻松地将其替换为兼容的组件(例如<input type="date" />),并且验证要容易得多。您仍然可能需要forwardRef.focus()说几句,但其他方面的痛苦会减少。