簡體   English   中英

如何將組件傳遞給孩子?

[英]How to pass components to children?

我有一個呈現鏈接和評論表單的簡單組件。 單擊該鏈接會聚焦評論表單。 為此,我使用在頂級組件中創建的 ref 並將其傳遞給兩個子組件。 這部分工作正常。

import { useRef } from "react";

export default function Commentable({children}) {
    const textareaRef = useRef();

    return (
      <>
           <CommentableButton formRef={textareaRef} />
           <CommentForm formRef={textareaRef} />
      </>
    )
}

export function CommentableButton({formRef}) {

    function focusForm(e) {
        e.preventDefault();
        formRef.current.focus();
    }

    return (
        <a href="#" onClick={focusForm}>Comment</a>
    )
}

export function CommentForm({formRef}) {
    return (
        <textarea ref={formRef}></textarea>
    )
}

我希望能夠像這樣將CommentButtonCommentForm傳遞給孩子:

export default function Commentable({children}) {
    const textareaRef = useRef();

    return (
      {children 
           button={<CommentableButton formRef={textareaRef} />}
           form={<CommentForm formRef={textareaRef} />}
      }
    )
}

所以我可以這樣使用它:

<Commentable>

    <div class="card">
        <div class="card-body">
            <h5>Media Title</h5>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur nec enim id dolor elementum imperdiet. Phasellus luctus ante elit, ac egestas diam posuere at.</p>
            <hr />
            {button}
        </div>
        <div class="card-footer">
            {form}
        </div>
    </div>

<Commentable>

我正在構建的應用程序中有許多可評論的實體,我想將所有可評論的行為保留在一個組件中,以便在需要時使用。 我嘗試了不同的方法來實現這一點,但似乎無法弄清楚。 我對 React 還很陌生,剛剛開始使用它。 請讓我知道是否有更好的方法來做到這一點。 我正在嘗試僅使用功能組件和掛鈎來做到這一點。 謝謝你的幫助!

這就是forwardRef發揮作用的地方。

Ref 轉發是一種通過組件自動將 ref 傳遞給它的一個子組件的技術。

首先,將評論按鈕和評論表單包裝在forwardRef函數中:

export const CommentButton = React.forwardRef((_props, ref) => {
  const focusForm = (e) => {
    e.preventDefault();
    ref.current.focus();
  };

  return (
    // eslint-disable-next-line jsx-a11y/anchor-is-valid
    <a href="#" onClick={focusForm}>
      Comment
    </a>
  );
});

export const CommentForm = React.forwardRef((_props, ref) => {
  return <textarea ref={ref}></textarea>;
});

然后創建可注釋組件,我們在其中初始化textareaRef並將textareaRef直接傳遞給子項。 在這里,我們在箭頭函數中渲染按鈕和表單組件,並使子組件可調用,以便我們可以將這兩個組件傳遞給可注釋組件。

export const Commentable = ({ children }) => {
  const textareaRef = React.useRef();
  const button = () => {
    return <CommentButton ref={textareaRef} />;
  };
  const form = () => {
    return <CommentForm ref={textareaRef} />;
  };

  return children(button(), form());
};

或者通過將組件直接作為參數傳遞:

export const Commentable = ({ children }) => {
  const textareaRef = React.useRef();
  return children(
     <CommentButton ref={textareaRef} />,
     <CommentForm ref={textareaRef} />
  );
};

這是最終的結果代碼和實現:

可評論的.js


import React from "react";

export const Commentable = ({ children }) => {
  const textareaRef = React.useRef();
  return children(
    <CommentButton ref={textareaRef} />,
    <CommentForm ref={textareaRef} />
  );
};

export const CommentButton = React.forwardRef((_props, ref) => {
  const focusForm = (e) => {
    e.preventDefault();
    ref.current.focus();
  };

  return (
    // eslint-disable-next-line jsx-a11y/anchor-is-valid
    <a href="#" onClick={focusForm}>
      Comment
    </a>
  );
});

export const CommentForm = React.forwardRef((_props, ref) => {
  return <textarea ref={ref}></textarea>;
});


您可以像這樣使用Commentable組件:

import { Commentable } from "./Commentable";

export default function App() {
  return (
    <Commentable>
      {(button, form) => {
        return (
          <div className="card">
            <div className="card-body">
              <h5>Media Title</h5>
              <p>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                Curabitur nec enim id dolor elementum imperdiet. Phasellus
                luctus ante elit, ac egestas diam posuere at.
              </p>
              <hr />
              {button}
            </div>
            <div className="card-footer">{form}</div>
          </div>
        );
      }}
    </Commentable>
  );
}

您正在尋找的模式可能是渲染道具模式。 https://reactjs.org/docs/render-props.html

您經常會看到以這種方式編寫的庫,其中包裝器組件期望單個函數作為子函數,該子函數具有傳遞給它的特定道具/增強道具。

const Commentable = ({ children }) => {
  const ref = useRef();

  return children({
    button: <Button ref={ref} />,
    form: <Form ref={ref} />
  });
};

<Commentable>
    {({ button, form }) => (
      <>
        <h1>Hello CodeSandbox</h1>
        {button}
        <h2>Start editing to see some magic happen!</h2>
        {form}
      </>
    )}
</Commentable>

你也可以使用鈎子:

const useCommentable = () => {
  const ref = useRef();
  return {
    button: <Button ref={ref} />,
    form: <Form ref={ref} />
  };
};

const MyComponent = () => {
     const {button, form} = useCommentable();
     return <>{button}{form}</>
}

我忘記了在這里的鈎子示例中是否需要做額外的工作來防止重新渲染。 無論如何,就像 React 經常說的那樣.. 稍后優化。

暫無
暫無

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

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