进行异步调用时,组件似乎不会在从同一个 thunk 分派的多个操作之间更新?

Components seem not update between multiple actions dispatched from same thunk when making async calls?

使用 react-native,当从 mapDispatchToProps 调用时,组件不会在从同一个 thunk 分派的多个动作之间更新吗?询问是因为我的用例是:尝试从 thunk 动作创建者执行异步 API 请求,但在两者之间设置和取消设置 isFetching 标志以在屏幕上显示加载微调器叠加层,如下所示:

// ComponentPresenter.js
export default class SigninScreenPresenter extends React.Component {
    constructor(props) {
        super(props);
    }
    componentDidUpdate() {
        console.log(`isFetching=${this.props.isFetching}`)
    }
    handlePress = () => {
        this.props.stateCallback()
    }
    render() {
        return(
        <SomeOtherStuff onPress={this.handlePress.bind(this)}/>
        <Spinner visible={this.props.isFetching} textContent={"Loading..."} textStyle={{color: '#FFF'}} />
        )
    }
}



// ComponentContainer.js
const mapStateToProps = (state, ownProps) => {
    // checking state changes
    console.log(`mapping state to props: state.session.isFetching=${state.session.isFetching}`)
    return {
        isFetching: state.session.isFetching,
        ownProps: ownProps
    }
}

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
      stateCallback: () => {
          dispatch(apiRequestThunk())
        }
  }
}

const ComponentContainer = connect(
  mapStateToProps,
  mapDispatchToProps
)(ComponentPresenter)

export default ComponentContainer



// actions/index.js
.....
export function setFetchingFlag() {
    return {type: SET_FETCHING}
}
export function unsetFetchingFlag() {
    return {type: UNSET_FETCHING}
}
export function apiRequestThunk() {
    return function (dispatch) {
        dispatch(setFetchingFlag())
        fetch(...making some REST request...)
            .then(
                (res) => {dispatch(someSuccessAction())}, 
                (error) => {dispatch(someFailureAction())})
        dispatch(unsetFetchingFlag())
    }
}
.....



// reducers/index.js
.....
const sessionReducer = (state=initialState.session, action) => {
    switch (action.type) {
        case FLAG_API_REQUEST:
            console.log('fetching API request')
            return Object.assign({}, state, {isFetching: true})
        case UNFLAG_API_REQUEST:
            console.log('done fetching API request')
            return Object.assign({}, state, {isFetching: false})
        default:
            return state
    }
}
.....
const rootReducer = combineReducers({
    session: sessionReducer,
    otherStateFields: otherReducers,
    .....
})
export default rootReducer

我在演示器组件中触发 handlePress() 时看到的控制台输出是

[14:49:03] fetching API request   (from reducers)
[14:49:03] mapping state to props: state.session.isFetching=true   (from container)
[14:49:03] done fetching API request    (from reducer)
[14:49:03] mapping state to props: state.session.isFetching=false    (from container)
[14:49:03] In component presenter: isFetching=false    (from presenter (I would expect another one before this with isFetching=True))

并且微调器从不渲染。

注意没有输出 "In component presenter: isFetching=true"(就好像它从不从映射到状态读取,即使输出表明它正在被调用)。这使得组件似乎没有使用 mapStateToProps 值进行实际更新,直到在演示者组件中调用的 mapDispatchToCallback 函数 finished 执行之后。

这里还有什么问题吗?有更多 'best-practice' 的方法吗? thunk 和 redux 的新手,所以任何调试建议将不胜感激。

我的建议是在异步请求 resolved/rejected 后调用 dispatch(unsetFetchingFlag())。此处您启动加载程序,然后发送 async 请求。这可以。但是,无需等待请求解析,您就可以取消设置加载程序。我相信这就是问题所在。查看此解决方案。

export function apiRequestThunk() {
    return dispatch => {
        // Start the loader
        dispatch(setFetchingFlag());

        // Send the async request
        fetch(...making some REST request...)
            .then(res => {
              // The request has been resolved. So stop the loader. 
              dispatch(someSuccessAction());
              dispatch(unsetFetchingFlag());
            }) 
            .catch(error => {
              // An error has occurred. So 
              // 1. Stop the loader. 
              // 2. Display the error, if require
              dispatch(unsetFetchingFlag());
              dispatch(someFailureAction());
            });
    }
}

使用async/await

export function apiRequestThunk() {
  return async dispatch => {
      // Start the loader
      dispatch(setFetchingFlag());

      try {
        // Send the async request
        const response= await fetch(...making some REST request...);

        // Once the request gets resolved, stop the loader. 
        // If any error occur in the request, then the error will be caught in the 'catch' block
        dispatch(someSuccessAction());
        dispatch(unsetFetchingFlag());
      }
      catch(error) {
        // An error has occurred. So 
        // 1. Stop the loader. 
        // 2. Display the error, if required
        dispatch(unsetFetchingFlag());
        dispatch(someFailureAction());
      }
  }
} 

也无需将 this 绑定到 onPress,因为您已经在使用箭头函数。 <SomeOtherStuff onPress={this.handlePress}/>