【问题标题】:React Native + Redux component renders before store action's completeReact Native + Redux 组件在 store 操作完成之前呈现
【发布时间】:2016-08-31 16:31:49
【问题描述】:

我已经使用 redux 对本机应用程序做出反应,用户在成功登录后会被导航到主组件。但是 home 组件在通过 store 接收用户配置文件之前被渲染。如果我使用“Home”组件作为连接组件,那么在重新渲染时它会收到配置文件。

这是一个正确的流程,或者我是否能够延迟渲染“主页”,直到商店填充了新数据。

这里是代码

类型

export const FETCH_PROFILE = 'FETCH_PROFILE';
export const UPDATE_PROFILE = 'UPDATE_PROFILE';
export const DELETE_PROFILE = 'DELETE_PROFILE';
export const FETCH_STREAMS = 'FETCH_STREAMS';

减速器

export default function profile(state = {}, action) {

  switch (action.type) {

  case types.FETCH_PROFILE:

    return {
      ...state,
      profile: action.profile
    }

  case types.UPDATE_PROFILE:

    return {
      ...state,
      profile: action.profile
    }

  case types.DELETE_PROFILE:

    return {
      ...state,
      profile: null
    };

  default:
    return state;
  }
}

动作

var PROFILE_KEY = "@myApp:profile";

export function fetchProfile() {
  return dispatch => {
    AsyncStorage.getItem(PROFILE_KEY)
      .then((profileString) => {
        dispatch({
          type: types.FETCH_PROFILE,
          profile: profileString ? JSON.parse(profileString) :  {}
        })
      })
  } 
}

export function updateProfile(data) {
  return dispatch => {
    AsyncStorage.setItem(PROFILE_KEY, JSON.stringify(data))
      .then(() => {
        dispatch({
          type: types.UPDATE_PROFILE,
          profile: data
        })
      })
  }
}

export function deleteProfile() {
  return dispatch => {
    AsyncStorage.removeItem(PROFILE_KEY)
      .then(() => {
        dispatch({
          type: types.DELETE_PROFILE
        })
      })
  }
}

登录组件

class Login extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      username: "",
      password: "",
      error: "",
      showProgress: false,
    };
  }

  _focusNextField(nextField) {
    this.refs[nextField].focus();
  }

  _onLoginPressed() {
    this.setState({showProgress: true});
    this._login();
  }

  async _login() {
    try {
      let response = await fetch( BASE_URL + url, {
                             method: 'POST',
                             headers: {
                               'Accept': 'application/json',
                               'Content-Type': 'application/json',
                             },
                             body: JSON.stringify({
                               user: {
                                 email: this.state.username,
                                 password: this.state.password,
                               }
                             })  
                           });

      let res = await response.text();
       if (response.status >= 200 && response.status < 300) {
          let user = JSON.parse(res);
          this.props.updateProfile(user.user);
          this.setState({showProgress: false});
          this.props.navigator.replace({name: 'Home'});
       }
       else {
         let error = JSON.parse(res);
         throw error.errors;
       }
    } catch(error) {
        this.setState({error: error});
        this.setState({showProgress: false});
        console.log("error " + error);
    }
  }

  render() {
    return (
        <View style={styles.loginBox}>
          <TextInput
            ref="username"
            value={this.state.username}
            placeholder="Username" 
            keyboardType="email-address"
            onChangeText={(username) => this.setState({username}) }
            onSubmitEditing={() => this._focusNextField('password')}/> 
          <TextInput 
            ref="password"
            placeholder="Password" 
            value={this.state.password}
            secureTextEntry={true} 
            onChangeText={(password) => this.setState({password}) }
            returnKeyType="go"/>
          <Button textStyle={{fontSize: 14}} onPress={this._onLoginPressed.bind(this)} style={{marginTop: 30}}>
            Sign In
            </Button>
        </View>
      );
  }
}

const styles = StyleSheet.create({
  loginBox: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    alignItems: 'stretch',
    margin: 10,
  }
});

var {updateProfile} = require('../Actions');
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';

module.exports = connect(
  null,
  (dispatch) => {
    return bindActionCreators({updateProfile}, dispatch)
  }
)(Login)

首页

class Home extends React.Component { 

  render() {
    return (
      <View style={{flex: 1, backgroundColor: '#fff'}}>
        <Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>I'm in the Drawer!</Text>
        <Text>Auth key : {this.props.profile ? this.props.profile.authentication_token : 'authentication_token'}</Text>
      </View>
    );
  }
}

//module.exports = Home;

import { connect } from 'react-redux';

module.exports = connect(
  (state) => {
    return {
      profile: state.profile
    }
  },
  null
)(Home)

【问题讨论】:

  • 你为什么不在&lt;Home/&gt; 中显示一个忙碌的微调器,直到组件接收到它需要的数据......这不是真正的反应问题,只是异步软件的性质
  • 我正在做,但是在 中我再次渲染了另一个组件,我需要为其配置文件才能进行另一个 api 调用。这有点困难。但是给定的解决方案真的很棒,感谢@caojs

标签: react-native redux


【解决方案1】:

如果您使用的是redux-thunk,您可以延迟转换,直到加载数据。你需要改变一些小事情。

return 添加到动作创建者。

export function updateProfile(data) {
  return dispatch => {
    return AsyncStorage.setItem(PROFILE_KEY, JSON.stringify(data))
      .then(() => {
        dispatch({
          type: types.UPDATE_PROFILE,
          profile: data
        })
      })
  }
}

添加await

if (response.status >= 200 && response.status < 300) {
  let user = JSON.parse(res);
  await this.props.updateProfile(user.user);
  this.setState({showProgress: false});
  this.props.navigator.replace({name: 'Home'});
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-27
    • 1970-01-01
    • 1970-01-01
    • 2017-11-11
    • 1970-01-01
    • 1970-01-01
    • 2017-04-23
    • 1970-01-01
    相关资源
    最近更新 更多