我目前正在学习redux,我正试图通过创建个人项目来学习。这个想法是创建一个食谱应用程序,用户可以在其中查看食谱,保存他们喜欢的食谱,并将他们喜欢的配方导出到购物列表中。
为了呈现食谱,我使用了两个组件。一个组件是单个配方,另一个组件使用单个配方组件映射不同的配方。我之所以将两者拆分为单独的组件,是因为我希望映射不同配方的组件能够被重用,也可以映射用户喜欢的配方(避免编写额外的代码来基本上执行相同的过程,即渲染一个包含不同配方的数组(。
为了保存我想使用redux的最喜欢的食谱,因为这(据我所知(允许我将状态分配到不同的组件(使用mapStateToProps和connect(。这应该允许我(如果我错了,请纠正我(在映射不同食谱的组件中使用最喜欢的食谱的状态。我还可以使用单个配方组件中的状态来创建一个按钮,用于将不同的配方添加到我的收藏夹中。出于这样或那样的原因,我无法让调度/冗余工作。在redux devtools中,我可以看到初始状态(一个空数组(,但一旦我尝试将一个配方添加到favoriteRecipe数组中,就不会发生任何事情。我试着让它工作了几天,但似乎什么都不起作用。
提前谢谢你帮我!
第一个文件:/redux/favoriteRecipes/favoriteRecipesTypes.js
export const ADD_TO_FAVORITE_RECIPES = 'ADD_TO_FAVORITE_RECIPES';
export const REMOVE_FROM_FAVORITE_RECIPES = 'REMOVE_FROM_FAVORITE_RECIPES';
export const CLEAR_FAVORITE_RECIPES = 'CLEAR_FAVORITE_RECIPES';
第二个动作创建者:/redux/favoriteRecipes/favoriteRecipesActions/js
import { ADD_TO_FAVORITE_RECIPES, REMOVE_FROM_FAVORITE_RECIPES, CLEAR_FAVORITE_RECIPES } from "./favoriteRecipesTypes";
export const addToFavoriteRecipes = (recipe) => {
return {
type: ADD_TO_FAVORITE_RECIPES,
payload: recipe
}
}
export const removeFromFavoriteRecipes = (recipe) => {
return {
type: REMOVE_FROM_FAVORITE_RECIPES,
payload: recipe
}
}
export const clearFavoriteRecipes = () => {
return{
type: CLEAR_FAVORITE_RECIPES
}
}
第三个减速器:/redux/favoriteRecipes/favoriteRecipesReducer.js
import { ADD_TO_FAVORITE_RECIPES, REMOVE_FROM_FAVORITE_RECIPES, CLEAR_FAVORITE_RECIPES } from "./favoriteRecipesTypes";
const initialFavoriteRecipes = {
favoriteRecipes: []
}
const favoriteRecipesReducer = (state = initialFavoriteRecipes, action) => {
switch(action.type) {
case ADD_TO_FAVORITE_RECIPES:
return {
...state,
favoriteRecipes: [...state.favoriteRecipes, action.payload]
}
case REMOVE_FROM_FAVORITE_RECIPES:
return {
...state,
favoriteRecipes: state.favoriteRecipes.filter(item => item !== action.payload)
}
case CLEAR_FAVORITE_RECIPES:
return {
...state,
favoriteRecipes: []
}
default:
return state
}
}
export default favoriteRecipesReducer;
第四个商店:/redux/store.js
import { createStore, applyMiddleware, compose} from "redux";
import favoriteRecipesReducer from "../redux/favoriteRecipes/favoriteRecipesReducer";
import logger from "redux-logger";
const store =
createStore(
favoriteRecipesReducer,
compose(
applyMiddleware(logger),
window.devToolsExtension ? window.devToolsExtension() : f => f
)
)
export default store;
第五:单独的配方组成部分(我省略了一些部分,以使其尽可能短(:
import React, {useState} from 'react';
import {connect} from 'react-redux';
import { addToFavoriteRecipes } from '../../redux/favoriteRecipes/favoriteRecipesActions';
export const Recipe = ({recipe}, props) => {
const [isOpen, setIsOpen] = useState(false);
return (
<div className="col-md-3">
<div className="card bwm-card">
<div className="card-title">
<h2>{recipe.title}</h2>
</div>
<img className="card-img-top" src={recipe.image} alt={recipe.title} />
<div className="card-subtitle">
<h3>
<b>Type: {recipe.type} </b>
</h3>
<h3>
<b>Category: {recipe.category}</b>
</h3>
<h3>
<b>Cooking time: {recipe.cookingTime} minutes</b>
</h3>
</div>
<div>//omitted part: show or hide full recipe depending on the state of isOpen</div>
<div>
<input type="submit" onClick={props.addToFavoriteRecipes} value="add to favorite recipe" />
</div>
</div>
</div>
);
};
const mapStateToProps = state => {
return{
favoriteRecipes: state.favoriteRecipes
}
}
const mapDispatchToProps = dispatch => {
return{
addToFavoriteRecipes: () => dispatch(addToFavoriteRecipes())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Recipe)
感谢您的回答!
就在我提出这个问题之后,我就把它变成了这样。
import React, {useState} from 'react';
import {connect} from 'react-redux';
import { addToFavoriteRecipes } from '../../redux/favoriteRecipes/favoriteRecipesActions';
import store from '../../redux/store';
export const Recipe = ({recipe}) => {
const [isOpen, setIsOpen] = useState(false);
return (
<div className="col-md-3">
<div className="card bwm-card">
<div className="card-title">
<h2>{recipe.title}</h2>
</div>
<img className="card-img-top" src={recipe.image} alt={recipe.title} />
<div className="card-subtitle">
<h3>
<b>Type: {recipe.type} </b>
</h3>
<h3>
<b>Category: {recipe.category}</b>
</h3>
<h3>
<b>Cooking time: {recipe.cookingTime} minutes</b>
</h3>
</div>
<div>
{isOpen ? (
<div className="card-body">
<div className="card-body-ingredient">
{recipe.ingredients.map((ingredient, i) => {
return (
<table>
<tr>
<th>Quantity</th>
<th>Ingredient</th>
</tr>
<tr>
<th>{ingredient[0]}</th>
<th>{ingredient[1]}</th>
</tr>
</table>
);
})}
</div>
<div className="card-body-cookingsteps">
{recipe.cookingSteps.map((cookingstep, i) => {
return <p>{cookingstep}</p>;
})}
</div>
<div>
<button
type="submit"
value="Hide full recipe"
onClick={() => setIsOpen(false)}>
Hide full recipe
</button>
</div>
</div>
) : (
<button
type="submit"
value="Show full recipe"
onClick={() => setIsOpen(true)}>
Show full recipe
</button>
)}
</div>
<div>
<input type="submit" onClick={() => store.dispatch(addToFavoriteRecipes(recipe))} value="add to favorite recipe" />
</div>
</div>
</div>
);
};
这似乎违背了使用mapStateToProps和mapDispatchToProps的全部目的。
mapStateToProps
和mapDispatchToProps
都将这些值映射到props
对象上。它们可以从props
对象中销毁。
export const Recipe = ({
addToFavoriteRecipes, // <-- destructure from props
recipe,
}) => {
const [isOpen, setIsOpen] = useState(false);
return (
<div className="col-md-3">
<div className="card bwm-card">
<div className="card-title">
<h2>{recipe.title}</h2>
</div>
<img className="card-img-top" src={recipe.image} alt={recipe.title} />
<div className="card-subtitle">
<h3>
<b>Type: {recipe.type}</b>
</h3>
<h3>
<b>Category: {recipe.category}</b>
</h3>
<h3>
<b>Cooking time: {recipe.cookingTime} minutes</b>
</h3>
</div>
<div>
// omitted part: show or hide full recipe depending on the state of isOpen
</div>
<div>
<input
type="submit"
onClick={addToFavoriteRecipes} // <-- pass as callback
value="add to favorite recipe"
/>
</div>
</div>
</div>
);
};