React Native& Redux:如何以及在何处使用componentWillMount()

时间:2017-03-14 20:25:07

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

我使用react-native和redux在facebook登录app上工作。现在我正面临一个问题:

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

3 个答案:

答案 0 :(得分:1)

根据您对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});
  }
}

答案 1 :(得分:1)

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

您可以找到有关反应组件生命周期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 :(得分:0)

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

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