2016-07-01 3 views
2

Я объясню, почему я хочу это сделать позже. Вот в чем проблема. У меня есть функция, которая возвращает обещание, как показано ниже:Функция ввода, которая возвращает обещание в состоянии redux

const testFunc =() => { 
    return new Promise((resolve, reject) => { 
    setTimeout(() => { 
     if (Math.random() > 0.5) { 
     resolve('succeeded'); 
     } else { 
     reject('failed'); 
     } 
    }, 1000); 
    }); 
}; 

Как и следовало ожидать, я могу вызвать его, как это прекрасно:

testFunc() 
    .then((result) => console.log(result)) // 'succeeded' 
    .catch((error) => console.log(error)); // 'failed' 

Или присвоить его переменной и назвать его, как этот

const testFuncVar = testFunc; 
testFuncVar() 
    .then((result) => console.log(result)) // 'succeeded' 
    .catch((error) => console.log(error)); // 'failed' 

Все это ожидается. Однако, как только я поместил функцию в состояние redux, затем вызовите ее оттуда, она больше не работает. Вот что я сделал (сильно упростил).

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)); 
    }; 
} 

ошибка я получил _promise2 is not defined. Обратите внимание, что имя переменной _promise2 должно быть из транспондера babel. Если I console.log(state.testFunc) или console.log(testFunc), я получил:

testFunc() { 
    return new _promise2.default(function (resolve, reject) { 
    if (Math.random() > 0.5) { 
     resolve('succeeded'); 
    } else { 
     reject('failed'); 
    } 
    }); 
} 

Так или иначе объект Promise потерялся всякий раз, когда функция помещается в Redux состоянии?

Но я нашел обходное решение. Если изменить функцию

const testFunc = (resolve, reject) => { 
    setTimeout(() => { 
    if (Math.random() > 0.5) { 
     resolve('succeeded'); 
    } else { 
     reject('failed'); 
    } 
    }, 1000); 
}; 

И называть его resolve и reject переданными в качестве параметров, то я хорошо.

// this works 
new Promise((resolve, reject) => state.testFunc(resolve, reject)) 
    .then((result) => console.log(result)) 
    .catch((error) => console.log(error)); 

Я задаюсь вопросом, почему это функция, которая возвращает обещание не работает, когда он положил в Redux магазине, но один без возвращения обещание работает?

Теперь о том, почему я хочу это сделать. То, что я пытаюсь достичь, - это иметь очередь заданий, которая периодически отправляет некоторые асинхронные действия и в зависимости от результата (разрешать или отклонять) делает что-то еще (например, повторить попытку или отправить уведомление). Я хочу динамически добавлять/удалять задания в очередь и из очереди, поэтому сложно иметь редуктор, который может обрабатывать все возможные действия. Похоже, это разумный способ приблизиться к нему. Я открыт для предложений.

+0

Это сбивает с толку, особенно ошибка, там, кажется, не будет '_promise2' ... ничего .. в опубликованном коде? – adeneo

+1

Я очень подозреваю, что ошибка, с которой вы столкнулись, не показана в этом фрагменте. Неважно, что возвращает функция, вы просто сохраняете ссылку на нее в магазине. – AlexG

+0

@adeneo '_promise2' должен быть от транслятора. Я отредактировал вопрос, чтобы сделать его более понятным. – realbug

ответ

2

С немного больше рыть , Я, наконец, понял, что проблема действительно не имеет никакого отношения к сокращению или обещанию. Это просто потому, что они testFunc добавляются в состояние redux через назначение initialState объект буквальный. Когда это делается так, привязка теряется, следовательно, ошибка _promise2 is undefined. На самом деле, если я добавлю testFunc к состоянию редукции динамически (например, с помощью создателя действия и редуктора), привязка сохраняется и все работает отлично. Вот более подробное объяснение проблемы https://stackoverflow.com/a/2702028/4401488.

Просто для справки, вот код для добавления testFunc в Redux состоянии через редуктор

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)); 
    }; 
} 
1

Вы должны использовать промежуточное программное обеспечение с Redux, такие как Redux Thunk

import { createStore, applyMiddleware } from 'redux'; 
import thunk from 'redux-thunk'; 
import rootReducer from './reducers/index'; 

// Note: this API requires [email protected]>=3.1.0 
const store = createStore(
    rootReducer, 
    applyMiddleware(thunk) 
); 

Затем написать свои действия так:

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); 
    }; 
} 

Вы также можете попробовать использовать Redux-Promise

+0

Я использую redux thunk. Но в этом случае моя цель - не отправлять асинхронные действия серии. Вместо этого я хочу динамически добавлять или удалять thunks (функции, возвращающие обещания) в состояние redux, и периодически планировать диспетчеризацию. – realbug

+1

Магазин предназначен для отслеживания состояния/данных приложения, а не для размещения функций. Не могли бы вы иметь структуру данных в вашем магазине, которая ссылается на thunks, а затем планировщик вызывает их на основе того, что находится в вашем магазине? – clhenrick