【问题标题】:Modal component does not render on a custom button component模态组件不会在自定义按钮组件上呈现
【发布时间】:2021-05-01 20:16:12
【问题描述】:

我正在尝试在按钮单击时呈现自定义和动态模式。例如,当单击“游戏”按钮时,我希望使用有关游戏的详细信息来呈现模式,当单击“银行”按钮时,我希望使用有关银行的详细信息来填充模式。

首先,当我将 onClick 函数添加到自定义按钮组件时,模态不会呈现。但是,当我将 onClick 函数放在常规按钮上时,模式会呈现。如何在任何组件上简单地添加 onClick 函数来呈现动态模式?

其次,我想用不同的数据填充每个模式。例如,“游戏”按钮将使用标题“游戏”等填充模态框。我正在使用道具来做到这一点,但这是最好的解决方案吗?

这是我到目前为止的代码,但是当我将 onClick 函数添加到组件时它被破坏了。

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

【问题讨论】:

  • 可以分享Button组件的实现吗?它是否将onClick 属性代理到任何可点击的底层 DOMNode/元素?如果您想使模态内容动态化,那么我建议将其作为ModalContext 状态的一部分并为其公开更新程序功能。我还看到您的ModalContext.Provider 没有渲染/包装children,因此它实际上无法为任何消费者提供上游上下文。
  • 检查我更新的 Button.js 实现代码。
  • 我明白了,它不会解构并将 onClick 属性传递给任何东西,因此它不可点击。你也可以分享ButtonStyle组件吗?
  • @DrewReese ButtonStyle 只是同一个 Button.js 文件中的样式化组件。就是这样:const ButtonStyle = styled.button....`

标签: javascript reactjs modal-dialog components react-context


【解决方案1】:

第一个问题:

我认为&lt;Button&gt; 组件的onClick 属性没有指向组件内部实际HTML buttononClick。 你能检查一下吗?而且如果你认为它的设置方式是正确的,那么你能分享一下组件的代码吗?

第二个问题

是的,还有另一种方法可以做到这一点。我认为是React Composition。您可以按以下方式构建模态:

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

我认为这种模式可以让您更好地控制该组件。

【讨论】:

    【解决方案2】:

    问题

    您没有将 onClick 属性传递给样式按钮组件。

    解决方案

    给定样式组件按钮:

    const ButtonStyle = styled.button``;
    

    自定义Button 组件需要将所有按钮道具传递给ButtonStyle 组件。

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

    如果还有其他按钮道具,那么您可以使用传播语法将它们收集到单个对象中,然后可以将其传播到 ButtonStyle 组件中。

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

    第二个问题

    对于第二个问题,我建议将打开/关闭/标题状态与Modal 组件一起完全封装在模态上下文提供程序中。

    这是一个示例实现:

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

    设置/打开模式的消费者示例:

    const OpenModalButton = ({ children }) => {
      const { openModal } = useContext(ModalContext);
    
      return <button onClick={() => openModal(children)}>{children}</button>
    }
    

    示例用法:

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

    演示

    【讨论】:

      猜你喜欢
      • 2017-10-06
      • 2018-01-08
      • 2021-08-26
      • 1970-01-01
      • 1970-01-01
      • 2010-11-20
      • 2022-11-26
      • 1970-01-01
      • 2018-12-15
      相关资源
      最近更新 更多