开发通用的React组件来打开和关闭任意表单

时间:2017-10-28 10:24:53

标签: reactjs

我在我的页面上打开并关闭了表单的以下代码段:

 <div>
   {this.state.editFormOpen?
   <div>
       <Link
          to=''
          onClick={()=>{this.setState({editFormOpen:false})}}>
          Close
       </Link>
       <PostForm
           onSubmit={(post)=>this.createPost(post)}
       />
   </div>:
   <Link
     to=''
     onClick={()=>{this.setState({editFormOpen:true})}}>
     Add post
  </Link>}
</div>

现在为了避免重复自己,我想将该代码重构为一个单独的<FormHandler/>组件,这样它就适用于任意形式,而不仅仅是 <PostForm/>。即,我需要能够将任何表单组件传递给<FormHandler/>

如何在React中执行此操作?

3 个答案:

答案 0 :(得分:1)

为了实现这一目标,您已经拥有了所需的一切。也许只需更改您呈现3.6的行并接受来自新组件的PostForm。有了它,您将能够在其中呈现您想要的任何形式。

请记住,您在props.children之外保留的业务逻辑越少越好。每个表单都应该知道在每个字段更改或提交时应该做什么。

例如,FormHandler 不应成为this.createPost的一部分,以防您想在整个代码中重复使用它。

FormHandler
class FormHandler extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      formOpen: false,
    }

    this.toggleFormOpen = this.toggleFormOpen.bind(this)
  }

  toggleFormOpen() {
    this.setState({
      formOpen: !this.state.formOpen,
    })
  }

  render() {
    return (
      <div>
        <button onClick={this.toggleFormOpen}>
          {this.state.formOpen ? 'Close' : 'Open'}
        </button>
        {this.state.formOpen && React.cloneElement(
          this.props.children,
          {
            onClose: this.toggleFormOpen
          }
        )}
      </div>
    )
  }
}

const PostForm = ({ onClose, onSubmit }) =>
  <form>
    <input type="text" placeholder="Post Name" />
    <input type="text" placeholder="Post Title" />
    <input type="text" placeholder="Date" />
    <button onClick={event => {
      event.preventDefault()
      onSubmit({ postName: '', postTitle: '', date: ''})
      onClose()
    }}>
      Submit
    </button>  
  </form>

const UserForm = ({ onClose, onSubmit }) => 
  <form>
    <input type="text" placeholder="First Name" />
    <input type="text" placeholder="Last Name" />
    <button onClick={event => {
      event.preventDefault()
      onSubmit({ firstName: '', lastName: '' })
      onClose()
    }}>
      Submit
    </button>  
  </form>

const App = () => 
  <div>
    <FormHandler>
     <PostForm
       onSubmit={formData => console.log('PostForm', formData)}
     />
    </FormHandler>
    <br />
    <FormHandler>
     <UserForm
       onSubmit={formData => console.log('UserForm', formData)}
     />
    </FormHandler>
  </div>

ReactDOM.render(
  <App />,
  document.getElementById('root')
)

答案 1 :(得分:1)

我将通过创建一个返回React Component的工厂来实现它,而不是将子项渲染为props

const FormHandlerFactory = ({Form = PostForm}) => {
    return class FormHandler extends React.Component {
       render() {
           return (
               <div>
                   {this.state.editFormOpen?
                   <div>
                       <Link
                          to=''
                          onClick={()=>{this.setState({editFormOpen:false})}}>
                          Close
                       </Link>
                       <Form
                           onSubmit={(post)=>this.createPost(post)}
                       />
                   </div>:
                   <Link
                     to=''
                     onClick={()=>{this.setState({editFormOpen:true})}}>
                     Add post
                  </Link>}
                </div>
            )
       }
    }
}

您可以将此工厂用作

const FormHandler = FormHandlerFactory({Form: YourCustomFormComponent});
const App = (props) => (
     <Form {...props}
)

答案 2 :(得分:1)

您可以创建一个无状态组件,该组件可以呈现您在该组件中传递的任何子项,您还需要将状态放在父组件中

const ToggleForm = ({ editFormOpen, editFormHandler, children }) => (
 <div>
   {editFormOpen?
   <div>
       <Link
          to=''
          onClick={() => editFormHandler(false)}>
          Close
       </Link>
       {children}
   </div>:
   <Link
     to=''
     onClick={() => editFormHandler(true)}>
     Add post
  </Link>}
</div>
);

class ParentCmp extends React.Component {
   constructor(props) {
     super(props);
     this.state = {
       editFormOpen: false,
     }
     this.editFormHandler = this.editFormHandler.bind(this);
     this.createPost = this.createPost.bind(this);
   }
   editFormHandler(boolValue) {
     this.setState({
       editFormOpen: boolValue
     });
   }
   render() {
      return (
        <div>
            <ToggleForm
              editFormOpen={this.state.editFormOpen}
              editFormHandler={this.state.editFormHandler}
            >
                <PostForm
                    onSubmit={(post)=>this.createPost(post)}
                />
            </ToggleForm>
        </div>
      )
   }
}