Сценарий: если в проекте есть две страницы A и B, соответствующие модели A и модели B, на каждой странице есть несколько асинхронных сетевых запросов, которые инициируются в эффектах, а возвращенные данные записываются в текущую модель через редуктор. штат.
Когда я покидаю страницу A или страницу B, я хочу очистить данные в соответствующей модели, чтобы не стать грязными при повторном использовании в следующий раз.
Я написал четкий редуктор в модели, в методе componentWillUnmount
отправка ({type: $ {model.namespace} / clear})
Пользователь переходит на страницу B со страницы A, и данные в модели A очищаются и восстанавливаются до исходного состояния.
Когда пользователь переходит на страницу B со страницы A, если асинхронный сетевой запрос возникает на странице A и переходит на страницу B до того, как сетевой запрос будет завершен, страница A сначала очистит данные модели A с помощью редуктора очистки, но когда сеть действует Когда запрос будет завершен, возвращенные данные будут перезаписаны в модель A, в результате чего получатся грязные данные из предыдущего бизнеса в модели A.
Могу ли я отменить указанные эффекты, когда покидаю страницу A, или отменить все эффекты в пространстве имен? (Аналогично отменить в redux-saga)
v2.2.3
Вы можете отслеживать изменения маршрутизации в подписках модели и вручную очищать состояние модели A, если страница не является страницей A (оставьте страницу A) или страницей A (введите страницу A).
Спасибо за ответы. Я пробовал этот метод. Нет проблем с очисткой самого состояния. Его можно очистить либо в componentWillUnmount, либо когда подписки отслеживают изменения маршрутизации. Проблема в том, что после очистки модального состояния данные, возвращаемые асинхронной операцией в эффектах Он все равно будет переписан в модальное состояние, что приведет к появлению грязных данных из предыдущего бизнеса.
Я даже отслеживаю изменения маршрутизации в подписках. Когда я покидаю страницу A, я использую unmodel для удаления модели A. Бесполезно вводить страницу A и вручную загружать модель A. Если асинхронная связь возвращается, пока модель A найдена, данные будут записаны независимо от того, является ли эта модель последней, использовавшейся в бизнесе, или новой загруженной моделью.
Итак, лучший способ - очистить состояние в модели и отменить все эффекты в текущем пространстве имен, но метод для вызова не найден. Искать совета.
Я столкнулся с проблемой исходного плаката. Я хотел отменить незавершенный эффект, когда компонент был удален, но обнаружил, что это невозможно. Dva, похоже, не предоставляет такого рода api @sorrycc
Можно ли отменить эффекты и разделить саги
@dlamon столкнулся с той же ситуацией и хотел очистить при переключении маршрута. Есть ли решение сейчас?
Не ожидается, что @KyrieChen очистит во время переключения маршрута, потому что после завершения переключения маршрута обмен данными может не возобновиться, а грязные данные все равно будут записаны обратно в очищенную область данных модели после возобновления связи.
Мой текущий подход заключается в создании области под-данных с UUID в области данных модели, соответствующей текущей транзакции, каждый раз, когда я вхожу в транзакцию (когда componentWillMount), которая используется для хранения данных, используемых в текущей транзакции. UUID записывается и сбрасывается при выходе из транзакции (componentWillUnmount). Подобно структуре модели ниже:
Если связь возвращается после модели очистки при записи данных, поскольку UUID, используемый текущим редуктором, является UUID, используемым в предыдущей транзакции, грязные данные будут записаны в область данных предыдущей транзакции и будут не будет сгенерирован для следующей транзакции.
Но и этот метод не годится: во-первых, он увеличивает логическую сложность, а во-вторых, получение начального значения требует добавления суждения о нулевом значении, что увеличивает сложность кода. Поскольку то, что я делаю, в основном предназначено для финансовой системы, я боюсь такого рода грязных данных, поэтому выбираю этот метод.
Я думаю, что лучший способ похож на механизм отмены эффектов в redux-saga, но сейчас dva, похоже, не поддерживает его.
Если у вас есть лучшее решение, @ 我
@dlamon Я тоже столкнулся с этим. Я сам написал демо, и мне кажется, что это немного проблематично https://codesandbox.io/s/yqwqpmvwvj
Отмените namespace
на products
на model
в методе effect
:
dispatch({ type: 'products/@<strong i="10">@CANCEL_EFFECTS</strong>' });
yield sagaEffects.fork(function*() {
yield sagaEffects.take(`${model.namespace}/@@CANCEL_EFFECTS`);
yield sagaEffects.cancel(task);
});
@ wss1942 Спасибо за ответ на этот метод. Я попробовал. Если отправка ({type: 'products / @ @CANCEL_EFFECTS '}) приведет к тому, что эффект в соответствующем модальном окне будет недействительным. Похоже на: # 796
@dlamon dva , похоже, не предоставляет API для очистки эффекта. Однако в эффекте, определенном в модели, можно записать несколько саг.
namespace: 'products',
effects: {
*start(){},
*stop(){},
watchLogin: [
function* ({ take, put, call, cancel, fork, cancelled }) {
yield take('start');
const timerTask = yield fork(timer)
const bgSyncTask = yield fork(bgSync)
yield take('stop')
yield cancel(bgSyncTask)
yield cancel(timerTask)
function* bgSync() {
try {
while (true) {
const result = yield call(delay, 5 * 1000);
yield put({ type: 'stop' })
}
} finally {
if (yield cancelled())
yield put({ type: 'log', payload: 'fetch🛑' })
}
}
function* timer(time) {
let i=0;
while (true) {
yield put({ type: 'log', payload: i++ })
yield delay(1000)
}
}
},
{ type: 'watcher' },
],
}
bgSync - это ваша асинхронная задача, вы можете запустить задачу с помощью action: start и отменить задачу с помощью
Кроме того, если асинхронная задача является сетевым запросом, может также потребоваться операция для отмены сетевого запроса.Например, axios можно отменить с помощью axios.CancelToken.
@ wss1942 Спасибо!
Таким образом, эффекты можно отменить. Отображать статус загрузки сложнее. Вы не можете напрямую использовать loading.effects, поставляемые с dva, для отображения статуса загрузки. Чтобы изменить его, вам нужно написать свой собственный код.
Я изменил его и выложил полный код модели
import { getProduct } from '@/services/Products';
import { isRespSucc, showErrorMsg } from '@/utils/utils';
const initState = {};
export default {
namespace: 'product',
state: initState,
effects: {
/**
在两个 Effects 之间触发一个竞赛(race)
如果task先结束,竞赛结束。
如果task未结束时收到cancel,race effect 将自动取消 task。
*/
*cancelable({ task, payload }, { call, race, take }) {
yield race({
task: call(task, payload),
cancel: take('cancel'),
});
},
/**
取消所有未完成的任务,并执行数据清理
*/
*clear(_, { put }) {
yield put.resolve({ type: 'cancel' });
yield put({ type: 'clearState' });
},
*getProduct({ payload }, { call, put, cancelled }) {
// eslint-disable-next-line
yield put.resolve({ type: 'cancelable', task: getProductCancelable, payload });
function* getProductCancelable(params) {
try {
// 调用网络请求
const response = yield call(getProduct, params);
// 返回结果判断
if (!isRespSucc(response)) {
showErrorMsg(response);
return;
}
// 取值
const { productName } = response.data;
// 调用reducer存值
yield put({
type: 'saveState',
payload: { productName },
});
} finally {
if (yield cancelled()) {
// TODO: 取消网络请求
}
}
}
},
*getCity(_, { call, put, cancelled }) {
// eslint-disable-next-line
yield put.resolve({ type: 'cancelable', task: getCityCancelable });
function* getCityCancelable() {
// TODO: 具体实现
}
},
reducers: {
saveState(state, { payload }) {
const newState = { ...state, ...payload };
return newState;
},
clearState() {
return initState;
},
},
};
При выходе из транзакции (componentWillUnmount) диспетчерская очистка может отменить все незавершенные эффекты в текущей модели, а getProductLoading и getCityLoading также могут использоваться в обычном режиме.
componentWillMount() {
const { dispatch } = this.props;
dispatch({
type: 'product/getProduct',
payload: {
productNumber: '123456',
},
});
dispatch({
type: 'product/getCity',
});
}
componentWillUnmount() {
const { dispatch } = this.props;
dispatch({
type: 'product/clear',
});
}
function mapStateToProps(state) {
return {
getProductLoading: state.loading.effects['product/getProduct'],
getCityLoading: state.loading.effects['product/getCity'],
};
}
Самый полезный комментарий
@ wss1942 Спасибо!
Таким образом, эффекты можно отменить. Отображать статус загрузки сложнее. Вы не можете напрямую использовать loading.effects, поставляемые с dva, для отображения статуса загрузки. Чтобы изменить его, вам нужно написать свой собственный код.
Я изменил его и выложил полный код модели
При выходе из транзакции (componentWillUnmount) диспетчерская очистка может отменить все незавершенные эффекты в текущей модели, а getProductLoading и getCityLoading также могут использоваться в обычном режиме.