javascript - Umiestnite funkciu, ktorá vracia promise, do stavu redux
Neskôr vysvetlím, prečo to chcem urobiť. Tu je problém. Mám funkciu, ktorá vracia sľub takto:
const testFunc = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
resolve('succeeded');
} else {
reject('failed');
}
}, 1000);
});
};
Ako sa očakávalo, môžem ho takto bez problémov vyvolať:
testFunc()
.then((result) => console.log(result)) // 'succeeded'
.catch((error) => console.log(error)); // 'failed'
Alebo to priradiť k premennej a zavolať to takto
const testFuncVar = testFunc;
testFuncVar()
.then((result) => console.log(result)) // 'succeeded'
.catch((error) => console.log(error)); // 'failed'
Tieto sú všetky očakávané. Avšak, keď funkciu vložím do stavu Redux a potom ju odtiaľ zavolám, už to nefunguje. Tu je to, čo som urobil (hrubo zjednodušené).
const initialState = {testFunc: testFunc};
// redux reducer, action creator, etc.
...
...
// somewhere later. Here I'm using redux-thunk to access redux state
function testFunInState() {
return (dispatch, getState) => {
const {testFunc} = getState();
// this is not working
testFunc()
.then((result) => console.log(result))
.catch((error) => console.log(error));
};
}
Chybu, ktorú som dostal, bolo _promise2 is not defined. Všimnite si, že názov premennej _promise2 by mal pochádzať z babel transpileru. Ak urobím console.log(state.testFunc) alebo console.log(testFunc), dostanem:
testFunc() {
return new _promise2.default(function (resolve, reject) {
if (Math.random() > 0.5) {
resolve('succeeded');
} else {
reject('failed');
}
});
}
Takže nejako sa objekt Promise stratil, kedykoľvek sa funkcia vloží do stavu redux?
Ale našiel som obchádzku. Ak zmením funkciu na
const testFunc = (resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
resolve('succeeded');
} else {
reject('failed');
}
}, 1000);
};
A zavolajte ho s resolve a reject odovzdanými ako parametre, potom som v poriadku.
// this works
new Promise((resolve, reject) => state.testFunc(resolve, reject))
.then((result) => console.log(result))
.catch((error) => console.log(error));
Zaujímam sa, prečo funkcia, ktorá vracia promise, nefunguje, keď ju vložíte do redux store, ale tá, ktorá promise nevracia, funguje?
Teraz k dôvodu, prečo to chcem robiť týmto spôsobom. To, čo sa snažím dosiahnuť, je mať frontu úloh, ktorá periodicky spúšťa niektoré asynchrónne akcie, a v závislosti od výsledku (vybavené alebo zamietnuté) robí niečo iné (napríklad opakovanie alebo odoslanie oznámenia). Chcem dynamicky pridávať/odstraňovať úlohy do fronty a z fronty, preto je ťažké mať reducer, ktorý dokáže spracovať všetky možné akcie. Pripadá mi to ako rozumný prístup. Som otvorený návrhom.
Odpoveď č. 1
Po trochu podrobnejšom skúmaní som nakoniec zistil, že problém naozaj nemá nič spoločné s reduxom alebo promise. Je to jednoducho preto, že testFunc sa pridáva do stavu redux cez priradenie k objektu literálu initialState. Keď sa to robí týmto spôsobom, väzba sa stratí, a preto vzniká chyba _promise2 is undefined. V skutočnosti, ak pridám testFunc do stavu redux dynamicky (napr. cez action creatora a reducer), väzba sa zachová a všetko funguje úplne správne. Tu je podrobnejšie vysvetlenie problému https://stackoverflow.com/a/2702028/4401488.
Len pre referenciu, tu je kód na pridanie testFunc do stavu redux cez reducer
const initialState = {};
// redux reducer
export default function jobReducer(state = initialState, action = {}) {
switch (action.type) {
case ADD_JOB:
return {job: action.job};
default:
return state;
}
}
// action creator
export function addJob(job) {
return {
type: ADD_JOB,
job: job
};
}
...
// add testFunc to redux state via action creator,
// I'm using redux-thunk here to access dispatch
function addTestFun() {
return (dispatch) => {
dispatch(addJob(testFunc));
};
}
...
// invocation of testFunc. Here I'm using redux-thunk to access redux state
function testFunInState() {
return (dispatch, getState) => {
const {testFunc} = getState();
// Now this is working
testFunc()
.then((result) => console.log(result))
.catch((error) => console.log(error));
};
}
Odpoveď č. 2
Musíte používať middleware s Reduxom, ako je Redux Thunk
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
// Note: this API requires redux@>=3.1.0
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
Potom napíš svoju akciu takto:
const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
function increment() {
return {
type: INCREMENT_COUNTER
};
}
function incrementAsync() {
return dispatch => {
setTimeout(() => {
// Yay! Can invoke sync or async actions with `dispatch`
dispatch(increment());
}, 1000);
};
}
Môžete tiež skúsiť použiť Redux-Promise
