【问题标题】:React Native & Redux : how and where to use componentWillMount()React Native 和 Redux:如何以及在何处使用 componentWillMount()
【发布时间】:2017-03-14 20:25:07
【问题描述】:

我使用 react-native 和 redux 开发带有 facebook 登录的应用程序。现在我面临一个问题:

Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.

所以我认为我必须在我的渲染方法之前使用 componentWillMount(),但我不知道如何使用它..

容器/登录/index.js

import React, { Component } from 'react';
import { View, Text, ActivityIndicatorIOS } from 'react-native';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as actionCreators from '../../actions';
import LoginButton from '../../components/Login';
import reducers from '../../reducers';
import { Card, CardSection, Button } from '../../components/common';


class Login extends Component {

  // how sould I use it ?
  componentWillMount() {

  }

  render() {
    console.log(this.props.auth);
    const { actions, auth } = this.props;
    var loginComponent = <LoginButton onLoginPressed={() => actions.login()} />;
    if(auth.error) {
      console.log("erreur");
      loginComponent = <View><LoginButton onLoginPressed={() => actions.login()} /><Text>{auth.error}</Text></View>;
    }
    if (auth.loading) {
      console.log("loading");
      loginComponent = <Text> LOL </Text>;
    }
    return(
      <View>
        <Card>
          <CardSection>
            { auth.loggedIn ? this.props.navigation.navigate('Home') : loginComponent }
          </CardSection>
        </Card>
      </View>
    );
  }
}

function mapStateToProps(state) {
  return {
    auth: state.auth
  };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(actionCreators, dispatch)
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(Login);

减速器:

import { LOADING, ERROR, LOGIN, LOGOUT } from '../actions/types';

function loginReducer(state = {loading: false, loggedIn: false, error: null}, action) {
  console.log(action);
  switch(action.type) {
    case LOADING:
      console.log('Inside the LOADING case');
      return Object.assign({}, state, {
        loading: true
      });
    case LOGIN:
      return Object.assign({}, state, {
        loading: false,
        loggedIn: true,
        error: null,
      });
    case LOGOUT:
      return Object.assign({}, state, {
        loading: false,
        loggedIn: false,
        error: null
      });
    case ERROR:
      return Object.assign({}, state, {
        loading: false,
        loggedIn: false,
        error: action.err
      });
    default:
      return state;
  }

}

export default loginReducer;

和行动:

import {
  LOADING,
  ERROR,
  LOGIN,
  LOGOUT,
  ADD_USER
} from './types';
import { facebookLogin, facebookLogout } from '../src/facebook';

export function attempt() {
  return {
    type: LOADING
  };
}

export function errors(err) {
  return {
    type: ERROR,
    err
  };
}

export function loggedin() {
  return {
    type: LOGIN
  };
}

export function loggedout() {
  return {
    type: LOGOUT
  };
}

export function addUser(id, name, profileURL, profileWidth, profileHeight) {
  return {
    type: ADD_USER,
    id,
    name,
    profileURL,
    profileWidth,
    profileHeight
  };
}

export function login() {
  return dispatch => {
    console.log('Before attempt');
    dispatch(attempt());
    facebookLogin().then((result) => {
      console.log('Facebook login success');
      dispatch(loggedin());
      dispatch(addUser(result.id, result.name, result.picture.data.url, result.picture.data.width, result.data.height));
    }).catch((err) => {
      dispatch(errors(err));
    });
  };
}

export function logout() {
  return dispatch => {
    dispatch(attempt());
    facebookLogout().then(() => {
      dispatch(loggedout());
    })
  }
}

如果您需要更多代码,这里是我的仓库: https://github.com/antoninvroom/test_redux

【问题讨论】:

    标签: reactjs facebook react-native redux react-redux


    【解决方案1】:

    componentWillMount 是创建组件时要运行的第一个函数。首先运行getDefaultProps,然后运行getInitialState,然后运行componentWillMount。只有当您使用 react.createClass 方法创建组件时,getDefaultPropsgetInitialState 才会运行。如果组件是扩展 React.Component 的类,则不会运行这些方法。如果可以的话,建议使用componentDidMount 而不是componentWillMount,因为您的组件仍然可以在componentWillMount 和第一次渲染之前更新。

    你可以找到更多关于 react 组件生命周期的信息here

    另外,建议在类构造函数中设置状态或默认道具,或者使用getDefaultPropsgetInitialState

    class MyComponent extends React.Component {
      constructor(props) {
        super(props);
        this.state = { bar: 'foo' };
      }
    
      static defaultProps = {
        foo: 'bar'
      };
    }
    

    编辑:这是处理登录的组件

    import React, { Component } from 'react';
    import { View, Text, ActivityIndicatorIOS } from 'react-native';
    import { bindActionCreators } from 'redux';
    import { connect } from 'react-redux';
    import * as actionCreators from '../../actions';
    import LoginButton from '../../components/Login';
    import reducers from '../../reducers';
    import { Card, CardSection, Button } from '../../components/common';
    
    class Login extends Component {
      componentDidMount() {
        // If user is already logged in
        if(this.props.auth.loggedIn) {
          // redirect user here
        }
      }
    
      componentWillReceiveProps(nextProps) {
        // If the user just log in
        if(!this.props.auth.loggedIn && nextProps.auth.loggedIn) {
          // Redirect user here
        }
      }
    
      render() {
        console.log(this.props.auth);
        const { actions, auth } = this.props;
        var loginComponent = <LoginButton onLoginPressed={() => actions.login()} />;
        if(auth.error) {
          console.log("erreur");
          loginComponent = <View><LoginButton onLoginPressed={() => actions.login()} /><Text>{auth.error}</Text></View>;
        }
        if (auth.loading) {
          console.log("loading");
          loginComponent = <Text> LOL </Text>;
        }
        return(
          <View>
            <Card>
              <CardSection>
                { auth.loggedIn ? this.props.navigation.navigate('Home') : loginComponent }
              </CardSection>
            </Card>
          </View>
        );
      }
    }
    
    function mapStateToProps(state) {
      return {
        auth: state.auth
      };
    }
    
    function mapDispatchToProps(dispatch) {
      return {
        actions: bindActionCreators(actionCreators, dispatch)
      };
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Login);
    

    【讨论】:

    • 对于登录组件,我有义务这样做吗?我只想登录并进入主视图并在主视图中获取状态
    【解决方案2】:

    根据您对 Ajay 回答的评论,您希望在组件中设置初始状态。为此,您需要在 constructor function 中设置状态。

    class Login extends Component {
      constructor(props) {
        super(props);
        this.state = {
          color: props.initialColor
        };
      }  
    

    如果您有异步获取的数据要置于组件状态,you can use componentWillReceiveProps.

    componentWillReceiveProps(nextProps) {
      if (this.props.auth !== nextProps.auth) {
        // Do something if the new auth object does not match the old auth object
        this.setState({foo: nextProps.auth.bar});
      }
    }
    

    【讨论】:

    • 我在登录视图中,如果用户已登录并希望将状态设置为“true”,如果它是真的,我需要这个构造函数/componentWillReceive 吗?
    • 如果是这样,我不认为你真的需要组件状态。如果 auth.loggedIn 为真,我会将用户导航到主屏幕。像这样:componentWillReceiveProps(nextProps) { if (nextProps.auth.loggedIn) { this.props.navigation.navigate('Home'); } } 您还需要将它包含在 componentDidMount 中:componentDidMount() { if (this.props.auth.loggedIn) { this.props.navigation.navigate('Home'); } }
    • 谢谢哥们!在 Home 容器中我必须放置构造函数?或 componentWillReceive ?
    • 我不确定您要在 Home 容器中执行什么操作,但如果您要设置的数据是异步获取的,例如在 API 调用中,您可以在 componentWillReceiveProps 中执行此操作。如果它是从父组件传递给组件的,则可以在构造函数中设置状态
    【解决方案3】:

    componentWillMount() 在安装发生之前立即调用。它在 render() 之前调用,因此在此方法中设置状态不会触发重新渲染。避免在此方法中引入任何副作用或订阅。

    如果您需要更多信息 componentWillMount() 阅读此https://developmentarc.gitbooks.io/react-indepth/content/life_cycle/birth/premounting_with_componentwillmount.html

    【讨论】:

    • 感谢您的回答,在我的情况下,我应该如何在 componentWillMount() 中定义我的状态?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多