Reputation: 2393
I have 3 items: Login
, Register
, and AccountForm
. The AccountForm
should be able to receive the Login
or the Register
components as props. I am still a little new to this so having trouble with the execution after having tried a few different things.
AccountForm
:
class AccountForm extends Component {
render() {
return (
<Container>
<Row>
<Col md="6" className="mx-auto d-flex align-items-center">
<Container className="form-container">
<Row>
<Image src={"/static/frontend/images/digibrain-bubble-bg-black-thin.svg"}
alt="DigiBrain logo"
fluid
/>
</Row>
<Row className="mt-4">
<Col>
<Container>
{ this.props.form } // this is where I would like to pass the forms into.
</Container>
</Col>
</Row>
</Container>
</Col>
</Row>
</Container>
);
}
}
Login
:
class Login extends Component {
state = {
username: "",
password: "",
}
static propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
}
onSubmit = e => {
e.preventDefault();
this.props.login(this.state.username, this.state.password)
}
onChange = e => this.setState({
[e.target.name]: e.target.value
});
render() {
if (this.props.isAuthenticated) {
return <Redirect to="/dashboard"/>;
}
const {username, password} = this.state;
return (
<>
<FormGroup>
<h3 className="form-header">Sign In</h3>
</FormGroup>
<Form onSubmit={this.onSubmit}>
<FormGroup>
<label>Username</label>
<input
type="text"
className="form-control"
name="username"
onChange={this.onChange}
value={username}
/>
</FormGroup>
<FormGroup>
<label>Password</label>
<input
type="password"
className="form-control"
name="password"
onChange={this.onChange}
value={password}
/>
<Container className="mb-2">
<p className="text-right">
<small>
<Link to="/register">Forgot Password?</Link>
</small>
</p>
</Container>
</FormGroup>
<FormGroup>
<Button
type="submit"
className="btn btn-primary btn-lg btn-block">
<i className="fas fa-sign-in-alt p-1"/>
Sign In
</Button>
<p className="text-center text-muted">
<small>
By signing in you agree to our <Link to="/terms-of-service">Terms
of
Service</Link> and <Link to="/privacy-policy">Privacy
Policy</Link>
</small>
</p>
<p className="text-center text-muted">
Need an account? <Link to="/register">Sign Up</Link>
</p>
</FormGroup>
</Form>
</>
);
}
}
.. and Register
is a similar form to Login
so no need to post it...
My routes look as such:
<Route exact path='/register/' component={Register}/>
<Route exact path='/login/' component={Login}/>
How can I wrap the AccountForm
around the Login
and Register
components?
Upvotes: 2
Views: 49
Reputation: 2393
While the other answers where helpful, I found a simpler solution which allowed me to keep the code execution at a lower-level. I had to pass the form as children, as I was originally trying to do:
AccountForm
:
class AccountForm extends Component {
render() {
return (
<Container>
<Row>
<Col md="6" className="mx-auto d-flex align-items-center">
<Container className="form-container">
<Row>
<Image src={"/static/frontend/images/digibrain-bubble-bg-black-thin.svg"}
alt="DigiBrain logo"
fluid
/>
</Row>
<Row className="mt-4">
<Col>
<Container>
{ this.props.children }
</Container>
</Col>
</Row>
</Container>
</Col>
</Row>
</Container>
);
}
}
Then I had to wrap the Login
component in the <AccountForm>
tags:
class Login extends Component {
state = {
username: "",
password: "",
}
static propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
}
onSubmit = e => {
e.preventDefault();
this.props.login(this.state.username, this.state.password)
}
onChange = e => this.setState({
[e.target.name]: e.target.value
});
render() {
if (this.props.isAuthenticated) {
return <Redirect to="/dashboard"/>;
}
const {username, password} = this.state;
return (
<AccountForm>
<FormGroup>
<h3 className="form-header">Sign In</h3>
</FormGroup>
<Form onSubmit={this.onSubmit}>
<FormGroup>
<label>Username</label>
<input
type="text"
className="form-control"
name="username"
onChange={this.onChange}
value={username}
/>
</FormGroup>
<FormGroup>
<label>Password</label>
<input
type="password"
className="form-control"
name="password"
onChange={this.onChange}
value={password}
/>
<Container className="mb-2">
<p className="text-right">
<small>
<Link to="/register">Forgot Password?</Link>
</small>
</p>
</Container>
</FormGroup>
<FormGroup>
<Button
type="submit"
className="btn btn-primary btn-lg btn-block">
<i className="fas fa-sign-in-alt p-1"/>
Sign In
</Button>
<p className="text-center text-muted">
<small>
By signing in you agree to our <Link to="/terms-of-service">Terms
of
Service</Link> and <Link to="/privacy-policy">Privacy
Policy</Link>
</small>
</p>
<p className="text-center text-muted">
Need an account? <Link to="/register">Sign Up</Link>
</p>
</FormGroup>
</Form>
</AccountForm>
);
}
}
This allowed me to keep the Route
the same while making the AccountForm
reusable:
<Route exact path='/login/' component={Login}/>
Upvotes: 0
Reputation: 353
You can use an arrow function
to create a dynamic component and send any parameter you want by using the render
prop.
<Route exact path='/register/' render={() => <AccountForm form={Register} />}/>
<Route exact path='/login/' render={() => <AccountForm form={Login} />}/>
This time you will be switching from component
to render
. The render, as the name implies, can receive a function to render your new component inline. This allows much more flexibility when determining the final component for this route.
You can read more about Route
and its render
prop here: https://reactrouter.com/web/api/Route/render-func
Upvotes: 1
Reputation: 59
We can create HOC - AccountForm and apply it to 'Login' and 'Register' components
For ready reference- https://reactjs.org/docs/higher-order-components.html
Upvotes: 1