简体   繁体   中英

Rendering functional component from inside a functional component

So I have a functional component which is a toolbar. Its parent is a Text editor. The toolbar has many child components which are buttons. On clicking one of these buttons, I want a modal to appear. The logic of useModal . But the FormatToolbarModal does not appear.

I have read that all the rendering of a component must be done by the top level custom component? But I am unsure where to go from there. I want this modal to be reusable as other options from the toolbar will use it.

index.jsx

ReactDOM.render(routes, document.getElementById("app"));

App.jsx

const App = () => {
  return (
    <TextEditor/>
  )
}

TextEditor.jsx

const TextEditor = () => {
  return(
    <FormatToolbar>
      <FormatToolbarBlock format="link" icon={link2} />
      <FormatToolbarBlock format="image" icon={image} />
    </FormatToolbar>
    ... Editor stuff
  )
}


const FormatToolbarBlock = ({ format, icon }) => {
  const editor = useSlate();
  const {isShowing, toggle} = useModal();

  return (
    <FormatButton
      onMouseDown={e => {
        if(format === 'link'){
          toggle(e);
          <FormatToolbarModal       <---- here is my issue
            isShowing={isShowing}  
            hide={toggle}
          />
          } else if {
          ...
          }
      }}
    />
  )
}

UseModal.jsx

const useModal = () => {
  const [isShowing, setIsShowing] = useState(false);

  function toggle() {
    setIsShowing(!isShowing);
  }

  return {
    isShowing,
    toggle,
  }
};

export default useModal;

FormatToolbarModal.jsx

const FormatToolbarModal = ({ isShowing, hide }) => isShowing ? ReactDOM.createPortal(
  <React.Fragment>
    <p>I am a modal</p>
  </React.Fragment>, document.body 
): null;

export default FormatToolbarModal;

Hopefully from this, you can see my issue clearer. Im new to React and hooks, so any advice is appreciated.

Thanks!

You're calling the function, but not passing the resulting JSX elements to anything that will render them. Think of the bootstrapping operation you use with the top-level component, where you pass the result into ReactDOM.render or similar. That's what puts it on the page. You need to do the same thing with the result of calling your modal function.

You have a couple of options:

  1. You might do it by having a flag that your function sets, and then conditionally rendering the modal within another component.

  2. You might render it as (in?) a portal .

React 101.

  1. React naming convention: Component names should follow pascal-case.

    eg: from your code showModal should be ShowModal.

also your code is not sufficient to understand the structure(how and where these components are being rendered). what i'm saying is there are many other possible ways this could go south, but this alone could make this bug.

Okay so as I suspect and as TJ Crowder mentioned. My FormatButton did not know how to render such a component. I moved the component like so, and wrapped it in a fragment. Now everything works.

For anyone having the same issue. Check out react portals. Also, this link helped: https://levelup.gitconnected.com/create-a-modal-with-react-hooks-357c8aae7c3f

TextEditor.jsx

const FormatToolbarBlock = ({ format, icon }) => {
  const editor = useSlate();
  const {isShowing, toggle} = useModal();

  return (
    <>
    <FormatButton
      onMouseDown={e => {
        if(format === 'link'){
          toggle(e);
          } else if {
          ...
          }
      }}
    />
    <FormatToolbarModal
      isShowing={isShowing}  
      hide={toggle}
    />
    </>
  )
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM