2016-06-09 17 views
10

Wdrażam aplikację Pusher w mojej aplikacji React + Redux Saga, ale mam kilka problemów z niektórymi wywołaniami zwrotnymi, w których nie można zastosować metod put(...). Użycie metod console.log(...) itp. Pokazuje, ale nie mogę put do stanu mojej aplikacji.Korzystanie z funkcji wywołania zwrotnego anonimowego funkcji

Mogę się mylić, jeśli chodzi o implementację funkcji asynchronicznych/generatora, ale w tej chwili utknąłem.

Mój kod do zilustrowania tego, co nie będzie ogień:

import { takeLatest } from 'redux-saga' 
import { call, put } from 'redux-saga/effects' 

// Pusher actions 
export const pusherConnecting =() => { 
    return { 
     type: ActionTypes.PUSHER_CONNECTING 
    } 
}; 

export const pusherConnectSucceeded = (client) => { 
    return { 
     type: ActionTypes.PUSHER_CONNECT_SUCCEEDED, 
     client: client 
    } 
}; 

const pusherConnectFailed = (exception) => { 
    return { 
     type: ActionTypes.PUSHER_CONNECT_FAILED, 
     message: exception 
    } 
}; 

// Pusher Saga 
function * connectPusher(action) { 
    try { 
     const pusher = yield call(Api.connectPusher, action.directory, function(subscription) { 
      subscription.bind(PUSHER_BIND_RELOAD, function() { 
       location.reload(true); 
      }); 

      subscription.bind(PUSHER_BIND_REQUEST_DATA, function(data) { 
       if (data) { 
        put(updateDirectory(data)); 
       } else { 
        put(requestDirectory(action.directory.id)); 
       } 
      }); 
     }); 

     pusher.connection.bind('connected', function() { 
      put(pusherConnectSucceeded(pusher)); 
     }); 

     yield put(pusherConnecting()); 

    } catch (e) { 
     yield put(pusherConnectFailed(e)); 
    } 
} 

export default function * pusherSaga() { 
    yield * takeLatest(ActionTypes.DIRECTORY_FETCH_SUCCEEDED, connectPusher); 
} 



// My Api.ConnectPusher 
export function * connectPusher(directory, subscription) { 
    var pusher = new Pusher(PUSHER_KEY, { 
     encrypted: true 
    }); 

    var channels = ["test1", "test2" ]; 

    for (var i = 0; i < channels.length; i++) { 
     // Take each channel and callback with the subscription 
     yield subscription(pusher.subscribe(channels[i])); 
    } 

    return pusher; 
} 

rozwiązanie oparte na @Sebastien

yield put(yield onConnect(pusher)); 

function onConnect(pusher) { 
    return new Promise((resolve, reject) => { 
     pusher.connection.bind('connected', function() { 
      resolve(pusherConnectSucceeded(pusher)); 
     }); 
    }); 
} 
+0

Co oznacza "nie jest trafiony"? Nie docierasz do tej linii? Jak sprawdzasz, używając debuggera? –

+0

Oznacza to, że nie mogę wystrzelić tej metody. Metoda 'put'method nie jest wywoływana w moim anonimowym wywołaniu metody. A może tak jest, ale państwo się nie zmienia (to moje pytanie). – janhartmann

+0

Dlaczego "może"? Wydaje się, że to byłaby ** naprawdę ** podstawowa rzecz do określenia, czy 'put' nie jest osiągane lub osiągane, ale nie ma pożądanego efektu. Użyłbym debuggera, aby śledzić, co dokładnie się dzieje, lub (i to jest ** bardzo dużo ** opcja drugiej klasy) wrzucenia do jakiegoś 'console.log's. (Ale w porównaniu do błąkania się z pochodnią 'console.log', używanie debuggera jest jak włączanie świateł.) –

Odpowiedz

6

Redux-saga nie dopuszcza do put bez użycia słowa kluczowego yield. Ułożenie tworzy prosty obiekt/efekt json, który musi zostać zinterpretowany/wykonany, a nie będzie, jeśli nie zostanie uzyskany.

Ponadto, nawet z , jeśli odbywa się to w oddzwonieniu, nie będzie interpretowane, ponieważ saga Redux nie ma możliwości uruchamiania wywołań zwrotnych w swoim tłumaczu. Będą po prostu uruchamiane jako normalne wywołania zwrotne i nic się nie stanie.

Jeśli subscription.bind ma zwrócić pojedynczy wynik, można zamiast tego zawrzeć to wywołanie w funkcji zwracającej obietnicę, a następnie wydać tę obietnicę.

Jeśli ma zostać zwrócony strumień wyników, może być konieczne utworzenie channel. Sądzę, że w przyszłości ktoś wyśle ​​coś, co z łatwością pozwoli przekształcić Observables w strumienie Redux-saga.

Pamiętaj, że jeśli nie musisz wielokrotnie rezygnować z subskrypcji/ponownego subskrybowania, łatwiejsze może być wprowadzenie tego kodu poza sagą i po prostu wykonaj:

 subscription.bind(PUSHER_BIND_RELOAD, function() { 
      location.reload(true); 
     }); 

     subscription.bind(PUSHER_BIND_REQUEST_DATA, function(data) { 
      if (data) { 
       reduxStore.dispatch(updateDirectory(data)); 
      } else { 
       reduxStore.dispatch((requestDirectory(action.directory.id)); 
      } 
     }); 
+0

** TO ** jest tym, co muszę wiedzieć. Opracuję rozwiązanie i zaktualizuję moją odpowiedź za pomocą rozwiązania. Wielkie dzięki! – janhartmann

+0

możesz podać prosty przykład "Jeśli subscription.bind ma zwrócić pojedynczy wynik, możesz zamiast tego zawrzeć to połączenie w funkcję, która zwraca obietnicę, a następnie wydać tę obietnicę"? – janhartmann

+0

Zaktualizowałem moje pytanie za pomocą mojego rozwiązania, czy uważasz, że jest wystarczająco dobre? – janhartmann

Powiązane problemy