问题
Here's an action that return a post list and the images inside each post. Previously, this action was only returning the post list. How to adapt the reducer and the component to associate which images belongs to which post?
Action
export const recipesListFetch = (page = 1) => {
return (dispatch) => {
dispatch(recipesListRequest());
return requests
.get(`/recipes?_page=${page}`)
.then(async (response) => {
const recipes = response["hydra:member"];
const imagesForRecipe = [];
for (let i = 0; i < recipes.length; i++) {
for (let j = 0; j < recipes[i].image.length; j++) {
const imageUrlProperty = recipes[i].image[j];
const image = await requests.get(`${imageUrl}`);
imagesForRecipe.push(image);
}
recipes[i].image = imagesForRecipe;
}
dispatch(recipesListReceived(response));
})
.catch((error) => dispatch(recipesListError(error)));
};
};
Reducer
export default(state = {
posts: null,
isFetching: false,
currentPage: 1,
pageCount: null
}, action) => {
switch (action.type) {
case RECIPES_LIST_REQUEST:
state = {
...state,
isFetching: true,
};
return state;
case RECIPES_LIST_RECEIVED:
state = {
...state,
posts: action.data['hydra:member'],
pageCount: hydraPageCount(action.data),
isFetching: false,
};
return state;
case RECIPES_LIST_ERROR:
return {
...state,
isFetching: false,
posts: null,
};
case RECIPES_LIST_ADD:
state = {
...state,
posts: state.posts ? state.posts.concat(action.data) : state.posts
};
return state;
case RECIPES_LIST_SET_PAGE:
return {
...state,
currentPage: action.page
};
default:
return state;
}
}
Component
class RecipesList extends React.Component {
render() {
const {posts} = this.props;
if (null === posts || 0 === posts.length) {
return (<Message message="Aucune recette trouvé"/>);
}
return (
<div className="container-fluid padding pt-5 responsive-card">
<div className="row padding">
{posts && posts.map(post => (
<div className="col-md-6 col-lg-3 add-padding" key={post.id}>
<Link to={`/recipes/${post.id}`}>
<div className="card mb-3 mt-3" >
<img src={???} alt="" className="img-recipe-list"/>
<div className="card-body">
<h3>{post.title}</h3>
<p className="card-text d-flex justify-content-center">
<small className="text-muted">{post.time}</small>
</p>
</div>
</div>
</Link>
</div>
))}
</div>
</div>
)
}
}
export default RecipesList;
I would like to render a card for each post with the image and the title of the post.
回答1:
The first issue i am seeing is that you are not returning the imagesForRecipe, instead you are returning the response.
export const recipesListFetch = (page = 1) => {
return (dispatch) => {
dispatch(recipesListRequest());
return requests
.get(`/recipes?_page=${page}`)
.then(async (response) => {
// i strongly advice to not mutate the response object
// im not sure how your request method works, but if response is immutable
// your recipes will never actually get added
// to prevent that you can dispatch a new object instead of the response
const recipes = response["hydra:member"];
for (let i = 0; i < recipes.length; i++) {
// move this into the first for loop, becuase you want to start with
// an empty array for every recipe
const imagesForRecipe = [];
for (let j = 0; j < recipes[i].image.length; j++) {
const imageUrlProperty = recipes[i].image[j];
const image = await requests.get(`${imageUrl}`);
imagesForRecipe.push(image);
}
// here you assign only the images for a specific recipe
recipes[i].image = imagesForRecipe;
}
// return a new object with updated recipes
const editedResponse = { ...response, "hydra:member": recipes };
dispatch(recipesListReceived(editedResponse));
})
.catch((error) => dispatch(recipesListError(error)));
};
};
I hope this helps :)
来源:https://stackoverflow.com/questions/62769213/associate-images-with-post-in-reactjs