我正在尝试使用Facebook API在页面上添加Facebook登录。当用户单击“使用Facebook登录”按钮时,我希望页面重定向到另一个页面。为此,我做了以下工作:

componentDidMount() {
  window.fbAsyncInit = function() {
    FB.init({
      appId            : '1947842912095857',
      autoLogAppEvents : true,
      xfbml            : true,
      version          : 'v2.10'
    });
    FB.AppEvents.logPageView();
    FB.getLoginStatus((response) => {
      if (response.status === 'connected') {
        console.log('Logged in.');
        this.setState({ loggedIn: true });
      }
      else {
      }
    });

  // login callback implementation goes inside the function() { ... } block
  FB.Event.subscribe('auth.statusChange', (response) => {
    if (response.authResponse) {
      console.log('Welcome!  Fetching your information.... ');
      FB.api('/me', (response) => {
        console.log('Good to see you, ' + response.name + '.');
        this.setState({ loggedIn: true });
        // if(!this.state.loggedIn){
        // }
      });
    } else {
      console.log('User cancelled login or did not fully authorize.');
    }
  });
}.bind(this);
  (function(d, s, id){
     var js, fjs = d.getElementsByTagName(s)[0];
     if (d.getElementById(id)) {return;}
     js = d.createElement(s); js.id = id;
     js.src = "//connect.facebook.net/en_US/sdk.js";
     fjs.parentNode.insertBefore(js, fjs);
   }(document, 'script', 'facebook-jssdk'));

    var s = '<div class="fb-login-button" ' +
        'data-scope="public_profile,email" data-size="large" ' +
        'data-show-faces="false" data-auto-logout-link="true" ' +
        'href="javascript:void(0)""></div>';

    var div = document.getElementById('social-login-button-facebook')
    div.innerHTML = s;
}


首先,我初始化Facebook API。然后,我调用FB.getLoginStatus()来查看用户是否已经登录。在回调中,将this.state.loggedIn设置为true即可正常工作。但是,在FB.Event.subscribe()函数中,当我调用this.setState函数时,出现以下错误:

Warning: setState(...): Can only update a mounted or mounting component.


我试图解决此问题,而我尝试的解决方案是检查用户是否尚未登录,然后设置状态。

if(!this.state.loggedIn){
  this.setState({ loggedIn: true });
}


然后我摆脱了错误。但是我不知道为什么。
有谁知道为什么在this.setState()中调用FB.getLoginStatus()而不在FB.Event.subscribe()中调用为什么有效,为什么仅在用户尚未登录时才设置状态的原因呢?

感谢您抽出宝贵时间阅读本文。

最佳答案

这与请求的异步性质有关。尽管可能会在某个时刻挂载组件,但是如果有待处理的请求直到挂载组件后才完成,那么您将尝试在已挂载的组件上setState

例如:

class LoginComponent extends Component {

    componentWillMount() {
        // This request will happen whenever the component mounts
        Request.get('/login-token').then(() => {
            dispatch({type: SET_TOKEN, token: 'blah blah'});

            // Whoops, what if there was already a login token
            // and the user was redirected? This will attempt to set
            // state on a component that has been unmounted due to redirect
            this.setState({loggedIn: true});
        });
    }

    componentWillReceiveProps(props) {
        // This will only redirect if there is already a token
        if (props.token) {
           browserHistory.push('/some-logged-in-page');
        }
    }

    render() {
        return (
            // ...
        );
    }
}


在此示例中,每次安装组件时,请求都将尝试获取令牌。但是我们正在检查令牌是否通过道具传入,并可能进行重定向。由于请求的异步性质,如果传递了令牌,并且用户已重定向,请求仍将完成并尝试setState,但届时该组件将已被卸载。

查看此react blog post,它讨论了与异步请求有关的问题,并提出了一些方法来安全地取消componentWillUnmount中的请求。

09-30 13:26
查看更多