Как передать переменные мутации в функцию рендеринга? - PullRequest
0 голосов
/ 22 марта 2019

У меня есть следующий дочерний компонент:

class SignIn extends React.Component {

    constructor(props) {
        super(props);
        this.onClick = this.handleClick.bind(this);
        this.state = {
            email: '',
            password: ''
        };
    }

    handleClick = () => {
        this.props.onClick(this.state.email, this.state.password);            
    }

    handleEmailChange = (e) => {
        this.setState({email: e.target.value});
    }

    handlePasswordChange = (e) => {
       this.setState({password: e.target.value});
    }

    render() {
        return (
            ...
            <Input id="email" name="email" autoComplete="email" autoFocus 
                        value={this.state.email} onChange={this.handleEmailChange}/>

            <Input name="password" type="password" id="password" autoComplete="current-password" 
                        value={this.state.password} onChange={this.handlePasswordChange}/>
            ...
        );
    }
}

Теперь от родителя у меня есть следующий компонент:

class App extends Component {
    constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
    this.state = {
        email: "",
        password: ""
    }
}

handleClick(e, p, request) {
    request();
}

render() {
    const { email, password } = this.state;
    console.log('render', email, password); // here I see the right state after click
    return (
        <ApolloProvider client={client}>
            <Mutation mutation={LOGIN} variables={{ email: email, password: password }} onError={() => {}}>
            {(request, result) => {
                const { data, loading, error, called } = result;
                if(!called) {
                    return <SignIn onClick={(e, p) => this.handleClick(e, p, request)} />;
                }
                if(error) {
                    return <div>Error</div>;
                }
                if(loading) {
                    return <div>Loading...</div>;
                }
                ...
                return <div>Mutation processed</div>;
            }}
            </Mutation>
        </ApolloProvider>
    );
    }
}

То, чего я хотел добиться, - это отдельный обработчик после нажатия кнопки и запуск мутации после некоторой логики. Однако таким образом переменные (электронная почта, пароль) всегда отправляются в сеть пустыми. Если я положу request прямо в ручку, то это работает.

Как я могу иметь обработчик вне функции render, чтобы инициировать запрос мутации с правильными значениями переменных? Я также очень хотел бы знать, почему эта конструкция не работает, а переменные пусты.

1 Ответ

0 голосов
/ 22 марта 2019

Я думаю, что проблема здесь заключается в строке:

this.onClick = this.handleClick.bind(this);

При неправильном связывании вы не будете запускать нужный метод. Это должно быть:

this.handleClick = this.handleClick.bind(this);

Следующее достигает того, что вы хотите. Я уменьшил его, потому что я ничего не знаю о вашей реализации Apollo, но, надеюсь, вы получите суть:


// SignIn.jsx

import React, { Component } from "react";

class SignIn extends Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
    this.state = {
      email: "",
      password: ""
    };
  }

  handleClick = () => {
    this.props.onClick(this.state.email, this.state.password);
  };

  handleEmailChange = e => {
    this.setState({ email: e.target.value });
  };

  handlePasswordChange = e => {
    this.setState({ password: e.target.value });
  };

  render() {
    return (
      <div>
        <input
          id="email"
          name="email"
          autoComplete="email"
          autoFocus
          value={this.state.email}
          onChange={this.handleEmailChange}
        />

        <input
          name="password"
          type="password"
          id="password"
          autoComplete="current-password"
          value={this.state.password}
          onChange={this.handlePasswordChange}
        />

        <button onClick={this.handleClick}>Click Me</button>
      </div>
    );
  }
}

export default SignIn;

// App.jsx

import React, { Component } from "react";
import ReactDOM from "react-dom";

import SignIn from "./SignIn";

class App extends Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
    this.state = {
      email: "",
      password: ""
    };
  }

  handleClick(e, p, request) {
    console.log("Requesting: ", request);
  }

  render() {
    const { email, password } = this.state;
    const request = "Your Apollo Request";
    console.log("render", email, password); // here I see the right state after click
    return (
      <div>
        <SignIn onClick={(e, p) => this.handleClick(e, p, request)} />;
      </div>
    );
  }
}

export default App;

...