Nothing here
Nothing here

Reputation: 2393

Passing components into components

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

Answers (3)

Nothing here
Nothing here

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

John
John

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

navintellis
navintellis

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

Related Questions