简体   繁体   English

模态组件不会在自定义按钮组件上呈现

[英]Modal component does not render on a custom button component

I am trying to render a custom and dynamic modal on button clicks.我正在尝试在单击按钮时呈现自定义和动态模式。 For example, when a "Game" button is clicked, I would like a modal to render with specfics about the game and when a "Bank" button is clicked, I would like the modal to populate with specfics about a bank.例如,当单击“游戏”按钮时,我希望使用有关游戏的规范来呈现模式,当单击“银行”按钮时,我希望模式中填充有关银行的规范。

First, when I add an onClick function to a custom button component, the modal does not render.首先,当我将 onClick function 添加到自定义按钮组件时,模态不会呈现。 However, when I put the onClick function on a regular button, the modal does render.但是,当我将 onClick function 放在常规按钮上时,模式会呈现。 How can I simply add an onClick function on any component to render a dynamic modal?如何在任何组件上简单地添加 onClick function 以呈现动态模态?

Second, I would like to populate each modal with differnet data.其次,我想用不同的数据填充每个模式。 For example, a "Game" button would populate the modal with a title of "Game" and so on.例如,“游戏”按钮将使用标题“游戏”等填充模态框。 I'm using props to do this, but is that the best solution?我正在使用道具来做到这一点,但这是最好的解决方案吗?

Here is the code I have so far, but it is broken when I add the onClick function to components.这是我到目前为止的代码,但是当我将 onClick function 添加到组件时它被破坏了。

// Navbar.js
import { ModalContext } from '../contexts/ModalContext'

function Navbar() {
  const [showModal, updateShowModal] = React.useState(false)
  const toggleModal = () => updateShowModal((state) => !state)

return(
<ModalContext.Provider value={{ showModal, toggleModal }}>
  <Modal
  title="Title"
  canShow={showModal}
  updateModalState={toggleModal}
  />
  </ModalContext.Provider>
 )

  // does not render a modal
  <Button
  onClick={toggleModal}
  type="navItem"
  label="Game"
  icon="windows"
  />

    // render a modal
    <button onClick={toggleModal}>Show Modal</button>
  )
}
import { ModalContext } from '../contexts/ModalContext'
// Modal.js
const Modal = ({ title }) => {
  return (
    <ModalContext.Consumer>
      {(context) => {
        if (context.showModal) {
          return (
            <div style={modalStyles}>
              <h1>{title}</h1>
              <button onClick={context.toggleModal}>X</button>
            </div>
          )
        }

        return null
      }}
    </ModalContext.Consumer>
  )
}
// modalContext.js
export const ModalContext = React.createContext()
// Button.js
function Button({ label, type = 'default', icon }) {
  return (
    <ButtonStyle buttonType={type}>
      {setIcon(icon)}
      {label}
    </ButtonStyle>
  )
}

First problem:第一个问题:

I think the onClick prop of the <Button> component is not pointing to the onClick of the actual HTML button inside the component.我认为<Button>组件的onClick道具没有指向组件内实际HTML buttononClick Could you please check that?你能检查一下吗? And if you think It's been set up in the right way, then can you share the code of the component?如果你认为它已经以正确的方式设置,那么你可以分享组件的代码吗?

Second Problem第二个问题

Yes, there's another way to do that.是的,还有另一种方法可以做到这一点。 And I think it's React Composition .我认为它是React Composition You can build the modal as the following:您可以按以下方式构建模态:

<Modal
  showModal={showModal}
  updateModalState={toggleModal}
>
  <div className="modal__header">{title}</div>
  <div className="modal__body">{body}</div>
  <div className="modal__footer">{footer}</div>
</Modal>

I think this pattern will give you more control over that component.我认为这种模式会让你更好地控制那个组件。

Issue问题

You are not passing the onClick prop through to the styled button component.您没有将onClick道具传递给样式按钮组件。

Solution解决方案

Given style-component button:给定样式组件按钮:

const ButtonStyle = styled.button``;

The custom Button component needs to pass all button props on to the ButtonStyle component.自定义Button组件需要将所有按钮道具传递给ButtonStyle组件。

// Button.js
function Button({ label, type='default', icon, onClick }) {
  return (
    <ButtonStyle buttonType={type} onClick={onClick}>
      {setIcon(icon)}
      {label}
    </ButtonStyle>
  )
}

If there are other button props then you can use the Spread syntax to collect them into a single object that can then be spread into the ButtonStyle component.如果还有其他按钮道具,那么您可以使用 Spread 语法将它们收集到单个 object 中,然后可以将其传播到ButtonStyle组件中。

// Button.js
function Button({ label, type = 'default', icon, ...props }) {
  return (
    <ButtonStyle buttonType={type} {...props}>
      {setIcon(icon)}
      {label}
    </ButtonStyle>
  )
}

Second Question第二个问题

For the second issue I suggest encapsulating the open/close/title state entirely in the modal context provider, along with the Modal component.对于第二个问题,我建议将打开/关闭/标题 state 与Modal组件一起完全封装在模态上下文提供程序中。

Here's an example implementation:这是一个示例实现:

const ModalContext = React.createContext({
  openModal: () => {},
});

const Modal = ({ title, onClose}) => (
  <>
    <h1>{title}</h1>
    <button onClick={onClose}>X</button>
  </>
)

const ModalProvider = ({ children }) => {
  const [showModal, setShowModal] = React.useState(false);
  const [title, setTitle] = React.useState('');

  const openModal = (title) => {
    setShowModal(true);
    setTitle(title);
  }

  const closeModal = () => setShowModal(false);

  return (
    <ModalContext.Provider value={{ openModal }}>
      {children}
      {showModal && <Modal title={title} onClose={closeModal} />}
    </ModalContext.Provider>
  )
}

Example consumer to set/open a modal:示例消费者设置/打开模式:

const OpenModalButton = ({ children }) => {
  const { openModal } = useContext(ModalContext);

  return <button onClick={() => openModal(children)}>{children}</button>
}

Example usage:示例用法:

function App() {
  return (
    <ModalProvider>
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        <h2>Start editing to see some magic happen!</h2>

        <OpenModalButton>Modal A</OpenModalButton>
        <OpenModalButton>Modal B</OpenModalButton>
      </div>
    </ModalProvider>
  );
}

Demo演示

编辑 modal-component-does-not-render-on-a-custom-button-component

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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