score:0

Accepted answer

You already have everything you need in order to accomplish that. Maybe just change the line where you render PostForm and accept props.children coming from your new component. With that you will be able to render any form you want inside of it.

Remember that the less business logic you keep outside of FormHandler the better. Each form should be aware of what to do on every field change or on submit.

For example, this.createPost should not be part of FormHandler in case you want to reuse it throughout your code.

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')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

score:1

I will go about it by making a factory that returns a React Component, than render the children as 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>
            )
       }
    }
}

You can use this factory as

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

score:1

You could create a stateless component that could render any children that you passed in that component you also need to put the states in the parent component

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

Related Query

More Query from same tag