React-Redux:如何从异步AJAX调用的响应中设置初始状态?

时间:2017-07-22 06:48:53

标签: reactjs react-redux

如何setState()从AJAX请求收到的响应,以便我可以在页面中显示它们?

 constructor(props)
 {
    super(props);
    this.state = {
        email: '',
        first_name: '',
        middle_name: '',
        country: '',
        country_code: '',
        mobile_number: '',
        gender: ''
    }
 }

componentDidMount()
{
    store.dispatch(getUserProfile())
    .then(() => {
        const user = this.props.userProfile.userProfile && this.props.userProfile.userProfile.data.data;
        this.setState({
          email: user.email,
          first_name: user.first_name
        });

    })
}

render()
{
    return (
       <div className="form-group col-sm-12">
            <label htmlFor="email">Email*</label>
            <input type="email" name="email" value={this.state.email || ''}/>
       </div>

        <div className="form-group col-sm-12">
            <label htmlFor="email">First Name*</label>
            <input type="email" name="email" value={this.state.first_name || ''}/>
       </div>
    )
}

显然,我不能将.then()与store.dispatch方法一起使用。

  

未捕获的TypeError:_store2.default.dispatch(...)。则不是函数

getUserProfile() action function

import axios from 'axios';

export function getUserProfile()
{
    return function(dispatch)
    {

        dispatch(userProfileSuccess(false));
        dispatch(userProfileError(null));

        const request = axios
        ({
            url: "http://testapi/auth/v1/user/details",
            method: "get",
            headers: {
                'Content-Type': 'application/json',
                'Authorization' : 'Bearer ' + localStorage.getItem('access_token')
            }
        })

        .then(function(response) { dispatch(userProfileSuccess(response)); })
        .catch(function(error) {
            console.log(error)
        });

        return {
            type: 'USER_PROFILE_SUCCESS',
            payload: request
        }

    };

}

function userProfileSuccess(userProfile)
{
    return {
        type: 'USER_PROFILE_SUCCESS',
        userProfile: userProfile
    };
}
function userProfileError(userProfileError)
{
    return {
        type: 'USER_PROFILE_ERROR',
        userProfileError: userProfileError
    };
}

export default getUserProfile;

在AJAX调用中,我试过:

.then(function(response) {
        return new Promise((resolve) => {
            dispatch(userProfileSuccess(response));
            resolve();
        });

    })

但是控制台报告了同样的错误。

我可以传递给store.dispatch的回调吗?对此有什么正确的解决方法?

3 个答案:

答案 0 :(得分:2)

您可以在componentDidMount()

中添加回调
componentDidMount()
{
    store.dispatch(getUserProfile(), () => {
        const user = this.props.userProfile.userProfile && this.props.userProfile.userProfile.data.data;
        this.setState({
          email: user.email,
          first_name: user.first_name
        });

    })
}

这可能不完全相同,我只是想让你知道如何使用箭头功能添加回调,这样你就不需要使用了。

答案 1 :(得分:1)

Redux将状态存储在Redux存储中,与React组件状态(想想setState)分开。你快到了。您需要做的是将结果数据从异步调度引导到redux存储,然后引导到本地组件状态。下面的步骤3和4。

  1. 发送异步操作以获取数据。
  2. 从承诺中派遣一个动作来填充redux状态。
  3. 写一个截取操作的reducer并填充redux状态。
  4. 使用connect函数
  5. Connect您的本地组件状态具有redux状态。

答案 2 :(得分:1)

当您使用redux时,您的redux存储应该跟踪api调用何时正在进行或已完成或遇到一些错误。因此,不应该传递任何回调或承诺,而是应该为每个事件分派一个动作,如处理,成功,错误等(你已经在getprofile函数中做了)。虽然我会说你很好地区分过程,成功,错误。例如,你的getprofile方法应该大致看起来像这样

export function getUserProfile()
{
    return function(dispatch)
    {

        dispatch(userProfileProcessing());

        const request = axios
        ({
            url: "http://testapi/auth/v1/user/details",
            method: "get",
            headers: {
                'Content-Type': 'application/json',
                'Authorization' : 'Bearer ' + localStorage.getItem('access_token')
            }
        })

        .then(function(response) { dispatch(userProfileSuccess(response)); })
        .catch(function(error) {
            dispatch(userProfileError(response))
            console.log(error)
        });
    };
}

这正是我喜欢的。如果你想要你的方式,那也没关系。

现在每次调度任何动作时,redux都会更新reducer状态。这就是你可以设置/重置一些标志的地方,让组件知道api调用发生了什么。所以你的减速器可能看起来像这样:

//getUserProfileReducer.js
userProfileReducer = (state = {}, action) => {
   switch (action.type) {
        case 'USER_PROFILE_PROCESSING':
          return({
           ...state,
           processing: true,
           success: false,
           fail: false,
           userProfile: null,
          })
       case 'USER_PROFILE_SUCCESS':
          return({
           ...state,
           processing: false,
           success: true,
           fail: false,
           userProfile: action.userProfile,
          })
       case 'USER_PROFILE_Error':
          return({
           ...state,
           processing: false,
           success: false,
           fail: true,
           userProfile: null,
          })
}

现在您需要做的就是从您的组件访问此状态,以便您可以根据该状态采取必要的操作。为此,您可以使用mapStateToProps函数将redux状态转换为组件的prop。

constructor(props)
 {
    super(props);
    this.state = {
        email: '',
        first_name: '',
        middle_name: '',
        country: '',
        country_code: '',
        mobile_number: '',
        gender: ''
    }
 }

componentWillReceiveProps(newProps){
   if(newProps.userProfileStatus.success){
   // The success flag is true so set the state
   const user = newProps.userProfileStatus;
        this.setState({
          email: user.email,
          first_name: user.first_name
        });
   }
   else if(newProps.userProfileStatus.processing){
       // Api call is in progress so do action according to that like show loader etc.
   }
}
componentDidMount()
{
    store.dispatch(getUserProfile())
}

render()
{
    return (
       ...
    )
}

const mapStateToProps = state => {
    return {
        userProfileStatus: state.userProfileReducer,
    }
}