如何从数组对象中的超链接获取数据并 return 结果?
How to fetch data from a hyperlink in in an object of arrays and return the result?
我的后端returns以下数据。对于某些数据,我需要获取一个超链接才能获取数据。虽然这是针对单个对象的,但非常简单。我很纠结如何从对象数组中获取数据。
{
count: 2,
next: null,
previous: null,
results: [
{
id: 3,
title: 'Story-2',
description: 'Law window student scientist between news receive. Sign require point.',
price: '0.00',
author: '23f1a20asdfsa9-8175-4aasdfdsaf54-9a42-27fesadfdsaff258fc86',
place: 3,
placeUrl: 'http://localhost:8000/api/v1/places/3/',
imagesUrl: 'http://localhost:8000/api/v1/story-images/?place=3',
titleImage: 'http://localhost:8000/media/story_media/example_jJiJGMr.jpg'
},
{
id: 4,
title: 'Test',
description: 'sdfdsdsfdsf',
price: '0.08',
author: '23f1a209-817sdfdsf5-4a54-9a42-27fef25sadfds8fc86',
place: 1,
placeUrl: 'http://localhost:8000/api/v1/places/1/',
imagesUrl: 'http://localhost:8000/api/v1/story-images/?place=4',
titleImage: 'http://localhost:8000/api/v1/stories/?limit=9&offset=0&author=23f1a209-8175-4a54-9a42-27fef258fc86'
}
]
}
我现在想访问 PlaceUrl 的数据(例如,包含名称、城市等)并将数据添加到原始对象。我目前的做法是这样的。不过感觉不对:
const selectStoriesList = (state) => state.story.storyList.results;
export const selectStoriesListView = createSelector(
selectStoriesList,
(selectStoriesList) => {
let preparedStories = [];
if (selectStoriesList && selectStoriesList.length > 0) {
const promises = selectStoriesList.map(async (item) => {
const place = await axios.get(item.placeUrl, tokenConfig());
return {
authorUsername: item.author,
authorNickname: "",
authorImage: "",
titleImage: item.titleImage,
title: item.title,
place: place.data.name,
city: place.data.city,
linkToProfile: "",
linkToPlace: "",
linkToStory: `www.ssdfsuy`,
storyPrice: item.price,
storyIsBought: "",
};
});
console.log(promises);
let preparedStories = Promise.all(promises).then((values) => {
console.log(values);
return values;
});
return Promise.all(promises);
// return Promise.all(promises);
} else {
return preparedStories;
}
}
);
获取调用需要什么样子?欢迎任何提示。
A selector 不是执行异步抓取的地方。它应该是来自您商店的简单 selection 数据。
您在这里处理的是两个实体类型之间的关系:story
和 place
。您需要将数据存储在您的商店 in a normalized way, possibly using createEntityAdapter 中,以便您可以通过其 ID 查找地点。
您可以通过多种方式触发获取地点:
在组件中
Return 只是 select 报道时的地点 ID。您的故事组件将呈现一个地点组件,例如 <Place id={3}/>
。 Place
组件将 select 来自商店的地点对象,并使用 useEffect
钩子到 dispatch
其 ID 的“请求地点”操作。
在 Thunk
payload creator函数的createAsyncThunk
action which you use to fetch the stories can dispatch
additional actions through the thunkAPI
argument。或者它可以执行多个 API 请求,并在包含地点和故事的单个操作中 return 数据。
这是最后一个想法的代码,尽管我实际上更喜欢基于组件的方法。
import {
configureStore,
createAsyncThunk,
createEntityAdapter,
createReducer,
createSelector
} from "@reduxjs/toolkit";
import axios from "axios";
import { uniq } from "lodash";
const tokenConfig = () => ({});
const placesAdapter = createEntityAdapter();
const storiesAdapter = createEntityAdapter();
export const placeSelectors = placesAdapter.getSelectors(
(state) => state.place
);
export const storySelectors = storiesAdapter.getSelectors(
(state) => state.story
);
const fetchStories = createAsyncThunk(
"fetchStories",
async (_, { getState }) => {
// fetch the stories
const storyRes = await axios.get("/api/v1/stories/", tokenConfig());
const storyData = storyRes.data;
// array of place ids for each story
const placeIds = storyData.results.map((story) => story.place);
// find which place ids are already in the state and can be skipped over
const loadedPlaceIds = placeSelectors.selectIds(getState());
// filter out duplicates and already loaded
const idsToFetch = uniq(
placeIds.filter((id) => !loadedPlaceIds.includes(id))
);
// fetch all places
const places = await Promise.all(
idsToFetch.map((id) => axios.get(`/api/v1/places/${id}/`, tokenConfig()))
);
// return your data
return {
places, // an array of place objects
storyData // the story data
};
}
);
export const storiesReducer = createReducer(
storiesAdapter.getInitialState({
storyList: {
count: 0,
next: null,
previous: null,
ids: []
}
}),
(builder) =>
builder.addCase(fetchStories.fulfilled, (state, action) => {
const data = action.payload.storyData;
// save all of the stories
storiesAdapter.upsertMany(state, data.results);
// save the list, but with just the ids for the stories
state.storyList = {
...data,
ids: data.results.map((story) => story.id)
};
})
);
export const placesReducer = createReducer(
placesAdapter.getInitialState(),
(builder) =>
builder.addCase(fetchStories.fulfilled, (state, action) => {
// save all of the places
placesAdapter.upsertMany(state, action.payload.places);
})
);
export const selectStoriesListView = createSelector(
// select the list of story ids
(state) => state.story.storyList.results,
// select the stories
(state) => state.story.entities,
// select the places
(state) => state.place.entities,
// combine all
(ids, stories, places) => {
// map ids to objects
const storyObjects = ids.map((id) => stories[id]);
// reformat
return storyObjects.map(({ author, titleImage, price, title, place }) => {
// get the place from id
const { name, city } = places[place];
return {
authorUsername: author,
authorNickname: "",
authorImage: "",
titleImage,
title,
place: name,
city,
linkToProfile: "",
linkToPlace: "",
linkToStory: `www.ssdfsuy`,
storyPrice: price,
storyIsBought: ""
};
});
}
);
export const store = configureStore({
reducer: {
story: storiesReducer,
place: placesReducer
}
});
我的后端returns以下数据。对于某些数据,我需要获取一个超链接才能获取数据。虽然这是针对单个对象的,但非常简单。我很纠结如何从对象数组中获取数据。
{
count: 2,
next: null,
previous: null,
results: [
{
id: 3,
title: 'Story-2',
description: 'Law window student scientist between news receive. Sign require point.',
price: '0.00',
author: '23f1a20asdfsa9-8175-4aasdfdsaf54-9a42-27fesadfdsaff258fc86',
place: 3,
placeUrl: 'http://localhost:8000/api/v1/places/3/',
imagesUrl: 'http://localhost:8000/api/v1/story-images/?place=3',
titleImage: 'http://localhost:8000/media/story_media/example_jJiJGMr.jpg'
},
{
id: 4,
title: 'Test',
description: 'sdfdsdsfdsf',
price: '0.08',
author: '23f1a209-817sdfdsf5-4a54-9a42-27fef25sadfds8fc86',
place: 1,
placeUrl: 'http://localhost:8000/api/v1/places/1/',
imagesUrl: 'http://localhost:8000/api/v1/story-images/?place=4',
titleImage: 'http://localhost:8000/api/v1/stories/?limit=9&offset=0&author=23f1a209-8175-4a54-9a42-27fef258fc86'
}
]
}
我现在想访问 PlaceUrl 的数据(例如,包含名称、城市等)并将数据添加到原始对象。我目前的做法是这样的。不过感觉不对:
const selectStoriesList = (state) => state.story.storyList.results;
export const selectStoriesListView = createSelector(
selectStoriesList,
(selectStoriesList) => {
let preparedStories = [];
if (selectStoriesList && selectStoriesList.length > 0) {
const promises = selectStoriesList.map(async (item) => {
const place = await axios.get(item.placeUrl, tokenConfig());
return {
authorUsername: item.author,
authorNickname: "",
authorImage: "",
titleImage: item.titleImage,
title: item.title,
place: place.data.name,
city: place.data.city,
linkToProfile: "",
linkToPlace: "",
linkToStory: `www.ssdfsuy`,
storyPrice: item.price,
storyIsBought: "",
};
});
console.log(promises);
let preparedStories = Promise.all(promises).then((values) => {
console.log(values);
return values;
});
return Promise.all(promises);
// return Promise.all(promises);
} else {
return preparedStories;
}
}
);
获取调用需要什么样子?欢迎任何提示。
A selector 不是执行异步抓取的地方。它应该是来自您商店的简单 selection 数据。
您在这里处理的是两个实体类型之间的关系:story
和 place
。您需要将数据存储在您的商店 in a normalized way, possibly using createEntityAdapter 中,以便您可以通过其 ID 查找地点。
您可以通过多种方式触发获取地点:
在组件中
Return 只是 select 报道时的地点 ID。您的故事组件将呈现一个地点组件,例如 <Place id={3}/>
。 Place
组件将 select 来自商店的地点对象,并使用 useEffect
钩子到 dispatch
其 ID 的“请求地点”操作。
在 Thunk
payload creator函数的createAsyncThunk
action which you use to fetch the stories can dispatch
additional actions through the thunkAPI
argument。或者它可以执行多个 API 请求,并在包含地点和故事的单个操作中 return 数据。
这是最后一个想法的代码,尽管我实际上更喜欢基于组件的方法。
import {
configureStore,
createAsyncThunk,
createEntityAdapter,
createReducer,
createSelector
} from "@reduxjs/toolkit";
import axios from "axios";
import { uniq } from "lodash";
const tokenConfig = () => ({});
const placesAdapter = createEntityAdapter();
const storiesAdapter = createEntityAdapter();
export const placeSelectors = placesAdapter.getSelectors(
(state) => state.place
);
export const storySelectors = storiesAdapter.getSelectors(
(state) => state.story
);
const fetchStories = createAsyncThunk(
"fetchStories",
async (_, { getState }) => {
// fetch the stories
const storyRes = await axios.get("/api/v1/stories/", tokenConfig());
const storyData = storyRes.data;
// array of place ids for each story
const placeIds = storyData.results.map((story) => story.place);
// find which place ids are already in the state and can be skipped over
const loadedPlaceIds = placeSelectors.selectIds(getState());
// filter out duplicates and already loaded
const idsToFetch = uniq(
placeIds.filter((id) => !loadedPlaceIds.includes(id))
);
// fetch all places
const places = await Promise.all(
idsToFetch.map((id) => axios.get(`/api/v1/places/${id}/`, tokenConfig()))
);
// return your data
return {
places, // an array of place objects
storyData // the story data
};
}
);
export const storiesReducer = createReducer(
storiesAdapter.getInitialState({
storyList: {
count: 0,
next: null,
previous: null,
ids: []
}
}),
(builder) =>
builder.addCase(fetchStories.fulfilled, (state, action) => {
const data = action.payload.storyData;
// save all of the stories
storiesAdapter.upsertMany(state, data.results);
// save the list, but with just the ids for the stories
state.storyList = {
...data,
ids: data.results.map((story) => story.id)
};
})
);
export const placesReducer = createReducer(
placesAdapter.getInitialState(),
(builder) =>
builder.addCase(fetchStories.fulfilled, (state, action) => {
// save all of the places
placesAdapter.upsertMany(state, action.payload.places);
})
);
export const selectStoriesListView = createSelector(
// select the list of story ids
(state) => state.story.storyList.results,
// select the stories
(state) => state.story.entities,
// select the places
(state) => state.place.entities,
// combine all
(ids, stories, places) => {
// map ids to objects
const storyObjects = ids.map((id) => stories[id]);
// reformat
return storyObjects.map(({ author, titleImage, price, title, place }) => {
// get the place from id
const { name, city } = places[place];
return {
authorUsername: author,
authorNickname: "",
authorImage: "",
titleImage,
title,
place: name,
city,
linkToProfile: "",
linkToPlace: "",
linkToStory: `www.ssdfsuy`,
storyPrice: price,
storyIsBought: ""
};
});
}
);
export const store = configureStore({
reducer: {
story: storiesReducer,
place: placesReducer
}
});