将引用其他函数的函数传递给React

时间:2019-03-07 11:10:09

标签: javascript reactjs

在我的应用程序中,主要组件定义了一个函数,该函数具有对本地函数的引用,如下所示:

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

    tokenizer({email, password}) {
        return this.props.client.query({
            query: getToken,
            variables: {email: email, password: password}
        }).then(response => {
            return response.data
        }).catch(error => {
            console.warn(error);
            return {}
        });
    }

    async fetchToken({email, password}) {
        const data = await this.tokenizer({email, password});
        this.props.updateToken({token: data.login});//redux dispatch to props
    }

    render() {
        if (this.props.token) {
            return (
                <Home />
            )
        } else {
            return <Login fetchToken={this.fetchToken} />;
        }
    }
}

子组件(即Login)将使用fetchToken函数,如下所示:

class Login extends Component {
    constructor(props) {
        super(props);
        this.state = {
            email: '',
            password: ''
        };
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

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

    handleSubmit(event) {
        event.preventDefault();
        this.props.fetchToken(this.state);
    }

    render() {
        return (
            <Form onSubmit={this.handleSubmit}>
                   // ... Form HTML here
            </Form>
        )
    }
}

现在,一旦提交表单,根据以下错误,fetchToken将无法引用this.tokenizerUncaught (in promise) TypeError: this.tokenizer is not a function

我可以通过tokenizer方法,但是它又引用了其他道具。因此,我必须通过任何与功能/状态/道具相关的功能,这感觉像是一种过大的功能。相反,只能通过在父级中引用fetchToken来调用它吗?

3 个答案:

答案 0 :(得分:1)

如果要在同一上下文中使用它们,则必须绑定所有方法。 最简单的方法是在类中为每种方法使用箭头功能。

class Root extends React.Component {

    tokenizer = async ({email, password}) => {
        return this.props.client.query({
            query: getToken,
            variables: {email: email, password: password}
        }).then(response => {
            return response.data
        }).catch(error => {
            console.warn(error);
            return {}
        });
    }

    fetchToken = async ({email, password}) => {
        const data = await this.tokenizer({email, password});
        this.props.updateToken({token: data.login});//redux dispatch to props
    }

    render() {
        if (this.props.token) {
            return (
                <Home />
            )
        } else {
            return <Login fetchToken={this.fetchToken} />;
        }
    }
}

答案 1 :(得分:1)

fetchToken没有引用this,因此您必须绑定它或使用箭头函数。要绑定它,您必须像在登录组件的构造函数中使用thishandleChange一样将其绑定到handleSubmit

作为箭头功能,您的fetchToken如下所示:

async fetchToken = ({email, password}) => {
    const data = await this.tokenizer({email, password});
    this.props.updateToken({token: data.login});//redux dispatch to props
}

我建议对令牌生成器进行同样的操作。

答案 2 :(得分:0)

如错误所示,执行以下代码行时出现类型错误:

const data = await this.tokenizer({email, password});

您正在使用tokenizer调用this函数,但实际上this现在并不指向同一对象。如果您console.log(this.tokenizer),它将给您undefined。是的您发现问题在于范围。让我向您介绍一下this的范围:

当它在对象方法内部时,函数的所有者就是对象。因此,this关键字已绑定到对象。

然而,当它在一个函数内部,独立函数或另一个函数内部时,this将始终引用全局范围。

这被称为 JavaScript怪癖,这意味着JavaScript中发生的某些事情并不十分简单,并且无法按照您的想法进行。开发人员还认为这是一个糟糕的设计选择,现在他们正在使用ES6的箭头功能进行补救。

您可以绑定开发人员在ES6之前使用的方法,或者现在只需使用箭头功能即可。像这样

async fetchToken = ({email, password}) => {
    const data = await this.tokenizer({email, password});
    this.props.updateToken({token: data.login});//redux dispatch to props
}

类似地,您可以使标记程序功能也像箭头功能一样。