简体   繁体   中英

Is this an efficient implementation of a higher-order component (HOC) in React?

I asked this question yesterday: React sharing method across components

import React from 'react';

class LoginForm extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            email: '',
            password: '',
        };

        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(e) {
        const target = e.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.name;

        this.setState({
            [name]: value
        });
    }

Since I'm reusing handleChange(e) many times throughout my application, I decided to separate it out into a higher-order component as so:

import React from 'react';

const withHandleChange = (WrappedComponent) => {
    return class extends React.Component {
        constructor(props) {
            super(props);

            this.state = {
            };
        }

        handleChange = e => {
            const target = e.target;
            const value = target.type === 'checkbox' ? target.checked : target.value;
            const name = target.name;

            this.setState({
                [name]: value
            });
        }

        render() {
            return (
                <WrappedComponent
                    handleChange={this.handleChange}
                    form={this.state}
                    {...this.props}
                />
            );
        }
    }
};

export default withHandleChange;

Instead of making LoginForm maintain the state of the input fields, I now have the HOC accomplish that, and I pass this state down as a prop called form . I also pass down the handleChange method as a prop.

And in the original LoginForm component, I render the following:

<input type="text" placeholder="Email" name="email" value={this.props.form.email} onChange={this.props.handleChange} />

I wrapped LoginForm as so:

const WrappedLoginForm = withHandleChange(LoginForm);

const LoginBox = props => (
    <div className="login-box">
        <WrappedLoginForm />
    </div>
);

Is this a valid implementation? My main two concerns are (1) passing down the state as a prop to WrappedComponent in the withHandleChange definition, and (2) rendering WrappedLoginForm since I've read you shouldn't use HOCs inside the render method.

As for (1), is this efficient? Is there a better way to accomplish what I'm doing?

As for (2), I think they meant that I shouldn't run the HOC function inside the render method, but simply using a wrapped component (as I do now) should be fine. However, I'm slightly confused and would appreciate some confirmation.

Any and all suggestions would be helpful. Thanks!

It's disallowed to use HOCs in the render lifecycle because of that below expression

const WrappedLoginForm = withHandleChange(LoginForm);

does declare a component. And you know render lifecycle might be executed more than one time depends on what exactly happens to your app. Then It results to be more than one time that declaration of the wrapped component will be executed which may lead to unexpected behavior. I think this is the root reason why it's disallowed.

To avoid this kind of mistake, it is very recommended to declare the wrapped component at the place the inner component is exported(or imported). Like: LoginForm.js

export default withHandleChange(LoginForm)

or

import LoginForm from 'somewhere'

const WrappedLoginForm = withHandleChange(LoginForm);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM