【问题标题】:React: call parent hook which results in child not being rendered safelyReact:调用父挂钩导致子无法安全渲染
【发布时间】:2021-04-28 10:17:15
【问题描述】:

我正在尝试在 React 中实现基于 JWT 的身份验证。我关注了this tutorial from 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 父级的钩子来从 axios 承诺的 .then() 调用中设置 JWT,但是父级将停止呈现登录页面,并且它是 axios 承诺jwt 已设置。我将如何巧妙地解决这个问题?

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);

【问题讨论】:

  • 尝试在设置令牌之前将您的 isLoading 设置为 false。设置令牌后,您的应用程序将重新呈现,EmployeeLogin 将不再存在,您无法更新状态未安装的组件。也许那是你的错误

标签: reactjs axios es6-promise


【解决方案1】:

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



 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
            });
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-04
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 2020-07-26
    • 2021-04-23
    • 1970-01-01
    相关资源
    最近更新 更多