Я новичок в redux-saga и уже пару дней искал решение моей проблемы, поэтому решил, что спрошу здесь, так как пришел пустой.
Я делаю правки в библиотеке microsoft botframework-webchat для проекта, над которым я работаю. Вместо использования прямой линии я пытаюсь сделать библиотеку botframework-webchat совместимой с signalR . В частности, я вношу изменения в пакеты core и component . Моя цель - имитировать c поток прямого сокращения строки, чтобы signalR работал в контексте библиотеки botframework-webchat.
Базовый c поток начинается с моего root проекта, простого веб-приложения React .
rootproject / WebChat. js
import ReactWebChat from 'botframework-webchat';
render() {
...
<ReactWebChat
className={`${className || ''} web-chat`}
signalR={this.signalRConnection}
//directLine={this.createDirectLine(token)}
store={store}
styleSet={styleSet}
/>
}
Для моих целей я отправляю либо соединение signalR, либо объект соединения directLine. Затем в рамках 'botframework-webchat' в пакете компонентов ReactWebChat проходит через серию передач и в конечном итоге оказывается здесь:
rootproject / botframework-webchat / botframework-webchat-component / Composer. js
useEffect(() => {
if (signalR) {
console.log("Dispatch signalR");
dispatch(
connectSignalRAction({
signalR
})
);
}
else {
dispatch(
createConnectAction({
directLine,
userID,
username
})
);
}
return () => {
dispatch(disconnect());
};
}, [dispatch, signalR, userID, username]);
И при отправке объекта прямого или сигнального соединения, это правильно отправляет соответствующее действие. Затем следует перехват этого действия. Это делается в базовом пакете botframework-webchat. Сначала я продемонстрирую этот поток, работающий через прямую линию.
rootproject / botframework-webchat / botframework-webchat-component / botframework-webchat-core / connect. js
const CONNECT = 'DIRECT_LINE/CONNECT';
const CONNECT_FULFILLED = `${CONNECT}_FULFILLED`;
const CONNECT_FULFILLING = `${CONNECT}_FULFILLING`;
const CONNECT_PENDING = `${CONNECT}_PENDING`;
const CONNECT_REJECTED = `${CONNECT}_REJECTED`;
const CONNECT_STILL_PENDING = `${CONNECT}_STILL_PENDING`;
export default function connect({ directLine, userID, username }) {
return {
type: CONNECT,
payload: {
directLine,
userID,
username
}
};
}
export { CONNECT, CONNECT_FULFILLED, CONNECT_FULFILLING, CONNECT_PENDING, CONNECT_REJECTED, CONNECT_STILL_PENDING };
Это срабатывает CONNECT
и находится здесь:
rootproject / botframework-webchat / botframework-webchat-component / botframework-webchat- core / connectionStatusToNotificationSaga. js
/* eslint no-magic-numbers: ["error", { "ignore": [0, 1, 2, 3, 4] }] */
import { call, put, takeLatest } from 'redux-saga/effects';
import { CONNECT } from '../actions/connect';
import createPromiseQueue from '../createPromiseQueue';
import setNotification from '../actions/setNotification';
const CONNECTIVITY_STATUS_NOTIFICATION_ID = 'connectivitystatus';
function subscribeToPromiseQueue(observable) {
const { push, shift } = createPromiseQueue();
const subscription = observable.subscribe({ next: push });
return {
shift,
unsubscribe() {
subscription.unsubscribe();
}
};
}
function* connectionStatusToNotification({ payload: { directLine } }) {
const { shift, unsubscribe } = subscribeToPromiseQueue(directLine.connectionStatus$);
console.log("subscribe connection status: " + directLine.connectionStatus$);
try {
let reconnecting;
for (;;) {
const value = yield call(shift);
switch (value) {
case 0:
case 1:
yield put(
setNotification({
id: CONNECTIVITY_STATUS_NOTIFICATION_ID,
level: 'info',
message: reconnecting ? 'reconnecting' : 'connecting'
})
);
break;
case 2:
reconnecting = 1;
yield put(
setNotification({
id: CONNECTIVITY_STATUS_NOTIFICATION_ID,
level: 'success',
message: 'connected'
})
);
break;
case 3:
case 4:
reconnecting = 1;
yield put(
setNotification({
id: CONNECTIVITY_STATUS_NOTIFICATION_ID,
level: 'error',
message: 'failedtoconnect'
})
);
break;
default:
break;
}
}
} finally {
unsubscribe();
}
}
export default function*() {
yield takeLatest(CONNECT, connectionStatusToNotification);
}
Мне удалось установить точки останова в проекте и перейти к приведенному выше коду, поэтому он идет первым. Для справки, вот магазин и саги.
rootproject / botframework-webchat / botframework-webchat-component / botframework-webchat-core / createStore.ts
// This is for the racing between sagaMiddleware and store
/* eslint no-use-before-define: "off" */
import { applyMiddleware, createStore } from 'redux';
import createSagaMiddleware from 'redux-saga';
import reducer from './reducer';
import sagaError from './actions/sagaError';
import sagas from './sagas';
export default function createWebChatStore(initialState, ...middlewares):any {
const sagaMiddleware = createSagaMiddleware({
onError: (...args) => {
const [err] = args;
console.error(err);
store.dispatch(sagaError());
}
});
const store = createStore(
reducer,
initialState || {},
applyMiddleware(...middlewares, sagaMiddleware)
);
sagaMiddleware.run(sagas);
return store;
}
rootproject / botframework-webchat / botframework-webchat-component / botframework-webchat-core / sagas. js
import { fork } from 'redux-saga/effects';
import clearSuggestedActionsOnPostActivitySaga from './sagas/clearSuggestedActionsOnPostActivitySaga';
import connectionStatusToNotificationSaga from './sagas/connectionStatusToNotificationSaga';
import connectionStatusUpdateSaga from './sagas/connectionStatusUpdateSaga';
import connectSaga from './sagas/connectSaga';
import connectSignalRSaga from './sagas/connectSignalRSaga';
import detectSlowConnectionSaga from './sagas/detectSlowConnectionSaga';
import emitTypingIndicatorToPostActivitySaga from './sagas/emitTypingIndicatorToPostActivitySaga';
import incomingActivitySaga from './sagas/incomingActivitySaga';
import markAllAsSpokenOnStopSpeakActivitySaga from './sagas/markAllAsSpokenOnStopSpeakActivitySaga';
import postActivitySaga from './sagas/postActivitySaga';
import sendEventToPostActivitySaga from './sagas/sendEventToPostActivitySaga';
import sendFilesToPostActivitySaga from './sagas/sendFilesToPostActivitySaga';
import sendMessageBackToPostActivitySaga from './sagas/sendMessageBackToPostActivitySaga';
import sendMessageToPostActivitySaga from './sagas/sendMessageToPostActivitySaga';
import sendPostBackToPostActivitySaga from './sagas/sendPostBackToPostActivitySaga';
import sendTypingIndicatorOnSetSendBoxSaga from './sagas/sendTypingIndicatorOnSetSendBoxSaga';
import speakActivityAndStartDictateOnIncomingActivityFromOthersSaga from './sagas/speakActivityAndStartDictateOnIncomingActivityFromOthersSaga';
import startDictateOnSpeakCompleteSaga from './sagas/startDictateOnSpeakCompleteSaga';
import startSpeakActivityOnPostActivitySaga from './sagas/startSpeakActivityOnPostActivitySaga';
import stopDictateOnCardActionSaga from './sagas/stopDictateOnCardActionSaga';
import stopSpeakingActivityOnInputSaga from './sagas/stopSpeakingActivityOnInputSaga';
import submitSendBoxSaga from './sagas/submitSendBoxSaga';
import submitSendBoxSagaSignalR from './sagas/submitSendBoxSagaSignalR';
import postActivitySagaSignalR from './sagas/postActivitySagaSignalR';
import sendMessageBackToPostActivitySagaSignalR from './sagas/sendMessageToPostActivitySagaSignalR';
import testSaga from './sagas/TestSaga';
export default function* sagas() {
// TODO: [P2] Since fork() silently catches all exceptions, we need to find a way to console.error them out.
yield fork(testSaga);
yield fork(clearSuggestedActionsOnPostActivitySaga);
yield fork(connectionStatusToNotificationSaga);
yield fork(connectionStatusUpdateSaga);
yield fork(connectSaga);
yield fork(connectSignalRSaga);
yield fork(detectSlowConnectionSaga);
yield fork(emitTypingIndicatorToPostActivitySaga);
yield fork(incomingActivitySaga);
yield fork(markAllAsSpokenOnStopSpeakActivitySaga);
yield fork(postActivitySaga);
yield fork(sendEventToPostActivitySaga);
yield fork(sendFilesToPostActivitySaga);
yield fork(sendMessageBackToPostActivitySaga);
yield fork(sendMessageToPostActivitySaga);
yield fork(sendPostBackToPostActivitySaga);
yield fork(sendTypingIndicatorOnSetSendBoxSaga);
yield fork(speakActivityAndStartDictateOnIncomingActivityFromOthersSaga);
yield fork(startDictateOnSpeakCompleteSaga);
yield fork(startSpeakActivityOnPostActivitySaga);
yield fork(stopDictateOnCardActionSaga);
yield fork(stopSpeakingActivityOnInputSaga);
yield fork(submitSendBoxSaga);
yield fork(submitSendBoxSagaSignalR);
yield fork(postActivitySagaSignalR);
yield fork(sendMessageBackToPostActivitySagaSignalR);
}
Поток работает при использовании прямой линии, но затем, когда я отправляю через объект подключения signalR, который отправляет
dispatch(
connectSignalRAction({
signalR
})
, действие отправляется, но не принимается сагой. В частности, вот действие и сага:
rootproject / botframework-webchat / botframework-webchat-component / botframework-webchat-core / connectSignalR. js
const CONNECT_SIGNALR = 'SIGNALR/CONNECT';
const CONNECT_SIGNALR_FULFILLED = `${CONNECT_SIGNALR}_FULFILLED`;
const CONNECT_SIGNALR_FULFILLING = `${CONNECT_SIGNALR}_FULFILLING`;
const CONNECT_SIGNALR_PENDING = `${CONNECT_SIGNALR}_PENDING`;
const CONNECT_SIGNALR_REJECTED = `${CONNECT_SIGNALR}_REJECTED`;
const CONNECT_SIGNALR_STILL_PENDING = `${CONNECT_SIGNALR}_STILL_PENDING`;
export default function connectSignalR({ signalR }) {
return {
type: CONNECT_SIGNALR,
payload: {
signalR
}
};
}
export { CONNECT_SIGNALR, CONNECT_SIGNALR_FULFILLED, CONNECT_SIGNALR_FULFILLING, CONNECT_SIGNALR_PENDING, CONNECT_SIGNALR_REJECTED, CONNECT_SIGNALR_STILL_PENDING };
rootproject / botframework-webchat / botframework-webchat-component / botframework-webchat-core / connectSignalRSaga. js
/* eslint no-magic-numbers: ["error", { "ignore": [0, 10] }] */
import { call, cancel, cancelled, fork, put, race, take, takeEvery, takeLatest } from 'redux-saga/effects';
import { CONNECT_SIGNALR, CONNECT_SIGNALR_PENDING } from '../actions/connectSignalR';
function* workerSaga() {
console.log("Hello from worker saga");
yield put({ type: CONNECT_SIGNALR_PENDING });
}
export default function*() {
// for (;;) {
// const {
// payload: { signalR }
// } = yield takeEvery(CONNECT_SIGNALR);
// const {
// payload: { signalR }
// } = yield takeEvery(CONNECT_SIGNALR, workerSaga);
yield takeLatest(CONNECT_SIGNALR, workerSaga);
}
Я пробовал несколько разных подходов в 'connectSignalRSaga. js', но, похоже, не могу запустить workerSaga (), что заставляет меня думать, что функция по умолчанию никогда не срабатывает. Я пробовал использовать точки останова и оператор отладчика, и он не останавливается в этой функции (но точки останова и операторы отладчика по какой-то причине все равно по большей части не работают).
Итак, мои вопросы:
Есть ли у вас какие-либо идеи, почему при использовании прямой линии выполняется действие «CONNECT», но когда с помощью signalr действие CONNECT_SIGNALR не выполняется?
Слегка отстает от topi c, но у меня возникли проблемы с настройкой Redux DevTools для этого проекта (это isomorphi c Приложение React). Я выполнил инструкции из https://github.com/zalmoxisus/redux-devtools-extension#usage, но расширение продолжает говорить мне «Магазин не найден». Я пробовал обернуть магазин пакетом 'redux-devtools-extension' npm, а также настроить составление вручную. Я полагаю, что установка этой настройки поможет разобраться в №1.