【问题标题】:React: Enforcing a child component under specific parentReact:在特定父级下强制执行子组件
【发布时间】:2018-09-09 02:14:04
【问题描述】:

我有一个这样的组件:

<Dialog id="_login" modal={true} onSubmit={() => console.log("x")} onCancel={() => console.log("C")} visible={true} >
    <DialogHead>
        Title Here
    </DialogHead>
    <DialogBody>
        <Field id="username" label="User Name" onChange={(id, value) => { console.log(id, value) }} />
        <Field id="password" label="Password" onChange={(id, value) => { console.log(id, value) }} />
    </DialogBody>
    <DialogFoot>
        <button onClick={e => console.log(e)}>Close</button>
    </DialogFoot>
</Dialog>

下面这个是&lt;Dialog&gt;渲染代码

public render() {
    return <div className="hx-dialog-outer" onClick={this.onCancel.bind(this)}>
        <div className="hx-dialog-inner" onClick={(e) => {e.stopPropagation()}}>
            <form name={this.props.id}>
                {this.props.children}
            </form>
        </div>
    </div>
}

如何强制在父元素下添加子元素?我的意思是,&lt;DialogHead&gt;&lt;DialogBody&gt;&lt;DialogFoot&gt;&lt;Dialog&gt; 容器之外不应该有效。比如下面这样使用,就会产生类似“ERROR: DialogHead must be nested in Dialog Component”的错误

<div>
    <DialogHead>
        Title Here
    </DialogHead>
</div>

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    我认为您可以使用 Containment 的概念,其中 Dialog 组件将是:

    function Dialog (props) {
      return (
        <div>
          {props.children}
        </div>
      );
    }
    

    现在你可以使用这个了:

    <Dialog id="_login" modal={true} onSubmit={() => console.log("x")} onCancel={() => console.log("C")} visible={true} >
        <DialogHead>
            Title Here
        </DialogHead>
        <DialogBody>
            <Field id="username" label="User Name" onChange={(id, value) => { console.log(id, value) }} />
            <Field id="password" label="Password" onChange={(id, value) => { console.log(id, value) }} />
        </DialogBody>
        <DialogFoot>
            <button onClick={e => console.log(e)}>Close</button>
        </DialogFoot>
    </Dialog>
    

    这是参考:Containment

    【讨论】:

    • OP 的意思是“我怎样才能做到让 DialogHead 在 Dialog 容器外使用时抛出错误”
    • 哦,好吧,在这种情况下,DialogHead 的子组件可以通过这个method 检测到他的父级,想法是子级可以检测到他的父级,如果不是他的父级,则抛出错误
    • 我已经检查了关于_reactInternalInstance的SO线程,但据说不能用于生产?这是一种对内部 React 工作的黑客攻击。
    【解决方案2】:

    React Context API 可能就是你想要的。

    // Parent <Dialog/>
    class Dialog extends React.Component {
      static childContextTypes = {
        dialog: PropTypes.object.isRequired
      }
      getChildContext() {
        return {
          dialog: this.props.dialog
        }
      }
    }
    
    // Children <DialogHeader/>, <DialogBody/>, <DialogFooter/>
    const DialogHeader = (props, context) {
      if (context.dialog == null)
        throw new Error('You should not use <DialogHeader/> outside a <Dialog/>')
      // return some markup
    }
    
    DialogHeader.contextTypes = {
      dialog: PropTypes.object.isRequired
    }
    

    自 React 16.3+ 起带有新的上下文 API

    const {Provider: DialogProvider, Consumer: DialogConsumer} = React.createContext(null)
    
    const Dialog = props =>
      <DialogProvider value={{dialog: props.dialog}}>
        {props.children}
      </DialogProvider>
    
    const DialogHeader = props =>
      <DialogConsumer>
        {({ dialog }) => 
          if (dialog == null) return new Error()
          // return some markup
        }
      </DialogConsumer>
    

    【讨论】:

    • 单独使用如何产生错误?由于&lt;DialogHead&gt;&lt;DialogBody&gt;&lt;DialogFoot&gt; 有一些应该在&lt;Dialog&gt; 组件中使用的道具。
    • 就我个人而言,我觉得为此使用上下文有点过分;但是我确实认为这是目前最好的解决方案....
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-15
    • 2010-11-10
    • 2021-02-02
    • 1970-01-01
    相关资源
    最近更新 更多