使用react-native,在从mapDispatchToProps调用时,组件是否在同一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))
并且Spinner永远不会渲染。
请注意,没有输出“在组件演示者中:isFetching = true”(就好像它从未从映射到状态读取一样,即使输出表明正在调用它也是如此)。这使得该组件似乎没有使用mapStateToProps值进行手动更新,直到在Presenter组件中调用的mapDispatchToCallback函数完成执行之后。
这里还有其他问题吗?有没有更多的“最佳实践”方法来做到这一点? thunk和redux的新功能,因此不胜感激任何调试建议。
答案 0 :(得分:1)
我的建议是一旦异步请求已解决/拒绝,就致电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());
});
}
}
使用异步/等待
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}/>