导航时如何停止/取消Redux传奇

时间:2019-04-07 17:18:20

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

我正在开发一个以本机响应的应用程序,在屏幕之间导航时,我需要停止/取消redux saga。我该怎么办?

我需要这个,因为我想避免过渡时出现延迟。 您可以观看视频,以更好地了解我的观点https://streamable.com/45qsa

我的代码在下面。

MindfulnessScreen.js

class MindFulness extends Component {


  componentDidMount() {
    this.props.dispatch(getMindFulness());
    this.props.dispatch(toggleBottomBar(true));
  }


  render() {
    const { isFetchingData, mindfulnessData, isLoggedIn, userType } = this.props;
    const header = mindfulnessData.header;
    const subHeader = mindfulnessData.subheader;
    const imageBanner = FILES_URL + mindfulnessData.image_banner;
    const mindFulnessDatas = mindfulnessData.children;
    return (
      <View style={{ flex: 1, backgroundColor: '#1F1F20' }}>
        {isFetchingData && <LoadingIndicator />}
        {/* <BottomBar screen={'MindFulness'} navigation={this.props.navigation} /> */}
        <ScrollView style={{ flexGrow: 1, marginBottom: 35 }}>
          {!isFetchingData && <FastImage
            style={{
              width: '100%',
              height: 137,
              display: "flex",
              alignItems: "center",
            }}
            resizeMode={FastImage.resizeMode.cover}
            source={{ uri: imageBanner }}
          >
            <View style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, justifyContent: 'center', alignItems: 'center', paddingLeft: 30, paddingRight: 30 }}>
              <Text style={{
                textAlign: 'center',
                fontSize: 20,
                color: '#FFFFFF',
                fontFamily: Theme.FONT_BOLD
              }}>{header}</Text>
              <Text style={{
                textAlign: 'center',
                fontSize: 14,
                paddingTop: 8,
                color: '#FFFFFF',
                fontFamily: Theme.FONT_MEDIUM
              }}>{subHeader}</Text>
            </View>
          </FastImage>}

          {this.renderData(mindFulnessDatas)}

          {!isFetchingData && isLoggedIn && userType == 0 && <View style={{
            width: width,
            height: 200,
            marginBottom: 30,
            borderRadius: 12,
            shadowRadius: 16,
            shadowOffset: { width: 0, height: 8 },
            shadowColor: "black",
            shadowOpacity: 0.47,
            elevation: 2
          }}
          >
            <FastImage style={{ width: '100%', height: '100%' }} source={unlockActivitiesBannerImage}>
              <View style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, justifyContent: 'center', alignItems: 'center' }}>
                <Text style={{
                  fontSize: 20,
                  color: '#FFFFFF',
                  textAlign: 'center',
                  position: 'absolute',
                  top: 40,
                  fontFamily: Theme.FONT_BOLD
                }}>{'All Synesthesia Meditations \n 7 days for free'}</Text>

                <CustomButton
                  disabled={false}
                  style={{
                    height: 50,
                    alignSelf: 'center',
                    alignItems: 'center',
                    justifyContent: 'center',
                    marginTop: 45,
                    width: 230,
                    borderRadius: 45,
                    backgroundColor: '#25B999',
                    opacity: 1
                  }}
                  title="Start free trial"
                  onPress={() => {
                    this.props.dispatch(setMenuItem('7 days for free'))
                    this.props.navigation.navigate('Pricing')
                  }}
                />
              </View>
            </FastImage>
          </View>}


        </ScrollView>
      </View>
    )
  }
}

function mapStateToProps(state) {
  return {
    isFetchingData: state.mindfulnessReducer.isFetchingData,
    mindfulnessData: state.mindfulnessReducer.mindfulnessData
  }
}

export default connect(mapStateToProps)(MindFulness);

AwarenessScreen与MindfulnessScreen.js相似

MindFulnessAction.js

import { ActionTypes } from '../constants/constants'

export function getMindFulness() {
  return {
    type: ActionTypes.GET_MINDFULNESS,
    payload: {}
  }
}

mindulnessReducer.js

import { ActionTypes } from '../constants/constants'

const initialState = {
  error: false,
  isFetchingData: false,
  mindfulnessData: [],
};

export const mindfulnessReducer = (state = initialState, action) => {
  switch (action.type) {
    case ActionTypes.GET_MINDFULNESS:
      return {
        ...state,
        isFetchingData: true
      }
    case ActionTypes.GET_MINDFULNESS_SUCCESS:
      return {
        ...state,
        isFetchingData: false,
        mindfulnessData: action.payload.node
      }
    case ActionTypes.GET_MINDFULNESS_FAIL:
      return {
        ...state,
        error: true,
        isFetchingData: false
      }
    default:
      return state
  }

}

api.js

let commonHeaders = {
  'Content-Type': 'application/json',
}

export const getMindFulness = (token) => fetch(`${baseUrl}node/337?token=${token}`, {
  method: 'GET',
  headers: {
    ...commonHeaders,
  },
}).then(response => response.json());

mindFulnessSaga.js

import { AsyncStorage } from 'react-native';

import { put, call, select } from 'redux-saga/effects'
import { ActionTypes } from '../constants/constants'
import { getMindFulness, getMindFulnessAnonymous } from '../api/api'

export const getMindfulnessData = (state) => state.mindfulnessReducer.mindfulnessData;

const MindFulnessSaga = function* (action) {
  const token = yield AsyncStorage.getItem('token');
  const mindfulnessData = yield select(getMindfulnessData);

  // if (mindfulnessData.length == 0) {
  if (token !== null) {
    const dataObject = yield call(getMindFulness, token);
    if (dataObject.status.success) {
      yield put({
        type: ActionTypes.GET_MINDFULNESS_SUCCESS,
        payload: {
          ...dataObject
        }
      })
    }
    else {
      yield put({
        type: ActionTypes.GET_MINDFULNESS_FAIL
      })
    }
  }
  else {
    const dataObject = yield call(getMindFulnessAnonymous);
    yield put({
      type: ActionTypes.GET_MINDFULNESS_SUCCESS,
      payload: {
        ...dataObject
      }
    })
  }
  // }
}

export default MindFulnessSaga

rootSaga.js

import { takeLatest } from 'redux-saga/effects'
import { ActionTypes } from '../constants/constants'
import MindFulnessSaga from './MindFulnessSaga'
import BeingAwareSaga from './BeingAwareSaga'


const rootSaga = function* () {
  yield takeLatest(ActionTypes.GET_MINDFULNESS, MindFulnessSaga)
  yield takeLatest(ActionTypes.GET_BEINGAWARE, BeingAwareSaga)
}

export default rootSaga

有什么建议吗?

谢谢

1 个答案:

答案 0 :(得分:2)

我的原始答案(我留在下面)不正确。我在谈论takeLatest效果时犯了一个错误,因为像the docs say

  

在分配给与模式匹配的商店的每个动作上产生传奇。 并自动取消,如果它仍在运行,则以前启动的任何先前的传奇任务。

因此,先前的MindFulnessSaga / BeingAwareSagatakeLatest效果自动取消。这并不意味着如果要取消以前的AJAX调用,也需要取消AJAX调用。

您可以通过将所有代码都放在try / final中并在finally块中对其进行管理,以管理传奇取消

import { cancelled } from 'redux-saga/effects'
function* MindFulnessSaga() {
  try {
    // ... your code
  } finally {
    if (yield cancelled())
      // the saga has been cancelled, cancel the AJAX request too
  }
}

这就是说:导航滞后可能与您没有缓存AJAX响应有关(但您在开始时就已经做了,因为您已经注释了// if (mindfulnessData.length == 0) {块)。



原始答案

您需要:

  • 用自定义无限循环(docs)替换takeLatest
  • forkdocs)不同的sagas,以便稍后可以canceldocs)将它们
  • 当用户导航到另一个屏幕时,
  • cancel分叉的长剑

请查看this answer of mine,以获取逐步说明。

让我知道您是否需要更多帮助