首页 > 解决方案 > React:调用父挂钩导致子无法安全渲染

问题描述

我正在尝试在 React 中实现基于 JWT 的身份验证。我从 digitalocean 学习了本教程,但使用了 axios(基于 promise)而不是 fetch API。

如果身份验证失败,则按要求显示错误消息,并且在成功登录时,将显示正确的页面。然而,React 会抛出以下错误:

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

我想这是因为我调用 loginpage 父级的钩子来.then()从 axios 承诺的调用中设置 JWT,但是一旦设置了 jwt,父级将停止呈现 loginpage 并且它是 axios 承诺。我将如何巧妙地解决这个问题?

function App() {
  const [token, setToken] = useState();

  if(!token) {
    return <EmployeeLogin setToken={setToken} />;
  }

  return (
    <main>
      <Switch>
        <Route path="/someroute" component={someComponent} exact />
      </Switch>
    </main>
  );
}

export default App;

// EmployeeLogin.jsx
const styles = theme => ({ ... });

class EmployeeLogin extends React.Component {
    constructor(props) {
        super(props);
        const { setToken } = this.props;
        this.state = {
            email: '',
            password: '',
            error: null,
            isLoading: false,
        };
        this.handleSubmitevents = this.handleSubmitevents.bind(this);
    }

    async handleSubmitevents(event) {
        event.preventDefault();
        const credentials = {
            email: this.state.email,
            password: this.state.password,
        }
        this.setState({
            isLoading: true,
            error: null,
        });
        axios.post('http://localhost:8080/account/employee/login', credentials, {
            headers: {
                "Content-Type": 'application/json', 'Accept': 'application/json'
            }
        })
            .then(res => {
                this.props.setToken(res.data.token); // Set the token to the parent (App.js)
            })
            .catch(error => {
                this.setState({
                    error: error.response.data.message, // Show error message on failure
                });
            })
            .then(() => {
                this.setState({ isLoading: false }); // Always stop the loading indicator when done
            });
    }

    componentWillUnmount() {
        // How to terminate the promise neatly here?
    }

    render() {
        const { classes } = this.props;
        return (
            <form className={classes.form} onSubmit={this.handleSubmitevents} noValidate>
                <TextField
                    required
                    value={this.state.email}
                    onChange={(e) => { this.setState({ email: e.target.value }); }}
                />
                <TextField
                    required
                    type="password"
                    value={this.state.password}
                    onChange={(e) => { this.setState({ password: e.target.value }); }}
                />
                <Button type="submit">Sign In</Button>
            </form>
        );
    }
}

EmployeeLogin.propTypes = {
    classes: PropTypes.object.isRequired,
    setToken: PropTypes.func.isRequired,
};

export default withStyles(styles)(EmployeeLogin);

标签: reactjsaxioses6-promise

解决方案


setToken设置为 false 后尝试调用,isLoading以便您可以尝试以下操作。



 async handleSubmitevents(event) {
        event.preventDefault();
        const credentials = {
            email: this.state.email,
            password: this.state.password,
        }
        this.setState({
            isLoading: true,
            error: null,
        });
        let responseToken = '';     // set responseToken to blank before calling api
        axios.post('http://localhost:8080/account/employee/login', credentials, {
            headers: {
                "Content-Type": 'application/json', 'Accept': 'application/json'
            }
        })
            .then(res => {
                responseToken = res.data.token;  // set responseToken here
            })
            .catch(error => {
                this.setState({
                    error: error.response.data.message, // Show error message on failure
                });
            })
            .then(() => {
                this.setState({ isLoading: false });
                this.props.setToken(responseToken);  // call props method from here
            });
    }


推荐阅读