redux thunk - как отсылать данные во вложенный массив после завершения обещания
Я хочу превратить весь текст по умолчанию в newArray в "новый текст". Затем отправьте массив с "новым текстом". Проблема в том, что функция отправки отправляет "текст по умолчанию". Похоже, это не ждет обещания. Что не так с настройкой моего обещания в приведенном ниже коде?
return dispatch => {
let newarray =[
{ post:[ {message:'default text'}, {message:'default text'}] }
]
let quests = newarray.map( (i) => {
return i.post.map( (item) => {
return axios.get(someLink).then( result =>{
item.message = 'new text'
return result
})
})
})
Promise.all(quests).then( () => {
dispatch({
type: constant.GET_SUCCESS,
payload: newarray
})
}).catch( () =>{
console.log('no result')
})
}
2 ответа
Ваша структура входных данных выглядит следующим образом:
[
{
post: [
{message:'default text'},
{message:'default text'}
]
}
]
Ваш код превращает его в это:
[
[
Promise<Axios>,
Promise<Axios>
]
]
Итак, на внешнем уровне нет способа узнать, когда внутренние обещания закончились. Нам нужны дополнительные слои обещаний для перемещения этой информации вверх по графу объектов. По сути, нам нужно:
Promise<[
Promise<[
Promise<Axios>,
Promise<Axios>
]>
]>
Так что обещание высшего уровня может разрешиться, когда все внутренние сделают. Код, который делает это, будет выглядеть очень похоже:
return function () {
var newarray = [{ post: [{ message: 'default text' }, { message: 'default text' }] }];
return Promise.all(newarray.map(function (i) {
return Promise.all(i.post.map(function (item) {
return axios.get(someLink).then(function (result) {
item.message = 'new text';
});
}));
})).then(function () {
return {
type: constant.GET_SUCCESS,
payload: newarray
};
}).catch(function (error) {
return {
type: constant.GET_ERROR,
payload: 'no result ' + error
};
});
};
Вы можете использовать функции стрелок, если вы думаете, что это улучшает ясность (я не делаю):
return () => {
var newarray = [{ post: [{ message: 'default text' }, { message: 'default text' }] }];
return Promise.all(newarray.map( i => Promise.all(
i.post.map( item => axios.get(someLink).then( result => {
item.message = 'new text';
}) )
))).then( () => ({
type: constant.GET_SUCCESS,
payload: newarray
})).catch( (error) => ({
type: constant.GET_ERROR,
payload: 'no result ' + error
}));
};
Общее замечание: я удалил функцию обратного вызова из вашего кода. Это противоречит философии, лежащей в основе обещаний вызывать обратные вызовы продолжения кода внутри них.
Вместо этого (по сути, ваш код):
function bla(callback) {
asyncFunction().then(someProcessing).then(callback);
}
сделай это:
function blaAsync() {
return asyncFunction().then(someProcessing);
}
Обратите внимание, что второй вариант больше не зависит от вызывающего. Он просто выполняет свою задачу и возвращает результат. Абонент может решить, что с ним делать:
blaAsync().then(function (result) {
// what "callback" would do
})
Вложенность, асинхронность и требование клонировать (или подражать) делают это немного хитрым:
Вы можете построить требуемый массив как внешнюю переменную:
function getMessagesAndDispatch(array) {
try {
let array_ = []; // outer variable, mimicking `array`
let outerPromises = array.map((a, i) => {
array_[i] = { 'post': [] }; // mimicking `a`
let innerPromises = a.post.map((item, j) => {
array_[i].post[j] = {}; // mimicking `item`
return axios.get(getOpenGraphOfThisLink + item.message).then(result => {
array_[i].post[j].message = result.data;
}).catch((e) => {
array_[i].post[j].message = 'default text';
});
});
return Promise.all(innerPromises);
});
return Promise.all(outerPromises).then(() => {
dispatch({
'type': constant.GET_SUCCESS,
'payload': array_
});
}).catch((e) => {
console.log('no result');
throw e;
});
} catch(e) {
// in case of a synchronous throw.
return Promise.reject(e);
}
}
В качестве альтернативы, можно обойтись без внешней переменной и разрешить обещаниям передавать данные:
function getMessagesAndDispatch(array) {
try {
let outerPromises = array.map(a => {
let innerPromises = a.post.map((item) => {
return axios.get(getOpenGraphOfThisLink + item.message).then(result => {
return { 'message': result.data }; // mimicking `item`
}).catch((error) => {
return { 'message': 'default text' };
});
});
return Promise.all(innerPromises).then((items_) => {
return { 'post': items_ }; // mimicking `a`
});
});
return Promise.all(outerPromises).then((array_) => {
dispatch({
'type': constant.GET_SUCCESS,
'payload': array_ // mimicking `array`
});
}).catch((e) => {
console.log('no result');
throw e;
});
} catch(e) {
// in case of a synchronous throw.
return Promise.reject(e);
}
}
За исключением ошибок с моей стороны, обе версии должны работать.
Ввод значений по умолчанию при ошибке может быть более полным, если это необходимо.