Я изучаю ReactJS и сейчас делаю небольшой проект для себя, чтобы управлять своими рецептами.
Я создаю свой проект, используя npx create-react-app <my-app>
. Я показываю галерею моего рецепта, в каждом рецепте есть изображение, название, описание и продолжительность приготовления. При нажатии на рецепт откроется другая страница с деталями рецепта со списком ингредиентов и этапов приготовления. У меня запущена страница галереи, и при нажатии на рецепт открывается страница сведений, но она не получает свойства рецепта, который я ей передаю.
Мои компоненты приложения / проекта: App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { Switch, Route } from 'react-router-dom'
import HomePage from './pages/HomePage';
import LoginPage from './pages/LoginPage';
import RecipesPage from './pages/RecipesPage';
import RecipeDetailsPage from './pages/RecipeDetailsPage';
import PlannedDinnerPage from './pages/PlannedDinnerPage';
import ShoppingListPage from './pages/ShoppingListPage';
import jsonUsers from './data/users'
import jsonKitchens from './data/Kitchens'
import jsonDishTypes from './data/DishTypes'
import jsonIngredients from './data/Ingredient'
import jsonRecipes from './data/recipes'
import jsonRecipeIngredients from './data/RecipeIngrediaent'
import jsonRecipesPreperationSteps from './data/RecipePreperationStep'
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
recipeId: null,
activeUser: null,
allUsers: jsonUsers,
allKitchens: jsonKitchens,
allDishTypes: jsonDishTypes,
allIngredients: jsonIngredients,
allRecipes: jsonRecipes,
allRecipesIngredients: jsonRecipeIngredients,
allRecipesPreperationSteps: jsonRecipesPreperationSteps,
activeUserRecipes: []
// hack for starting with my recipes
// activeUserRecipes: jsonRecipes.filter(recipe => recipe.userId === 1)
}
this.handleLogout = this.handleLogout.bind(this);
this.handleLogin = this.handleLogin.bind(this);
this.addRecipe = this.addRecipe.bind(this);
console.log(this.state.allRecipes);
}
handleLogout() {
this.setState({ activeUser: null });
}
handleLogin(activeUser) {
const activeUserRecipes = this.state.allRecipes.filter(recipe => recipe.userId === activeUser.id)
this.setState({ activeUser, activeUserRecipes });
}
addRecipe(newRecipe) {
//const {activeUser, allRecipes, activeUserRecipes} this.state.activeUser
// 1) add id and user to the recipe
newRecipe.userId = this.state.activeUser.id;
newRecipe.id = this.state.allRecipes[this.state.allRecipes.length - 1].id + 1;
// 2) update all recipes and active user recipes
const allRecipes = this.state.allRecipes.concat(newRecipe);
const activeUserRecipes = this.state.activeUserRecipes.concat(newRecipe);
this.setState({ allRecipes, activeUserRecipes });
}
render() {
// const activeUser = this.state.activeUser;
const { recipeId, activeUser, allUsers,
allRecipes,
allKitchens,
allDishTypes,
allIngredients,
allRecipesIngredients,
allRecipesPreperationSteps,
activeUserRecipes } = this.state;
return (
<Switch>
<Route exact path="/">
<HomePage activeUser={activeUser} handleLogout={this.handleLogout} />
</Route>
<Route path="/login">
<LoginPage users={allUsers} handleLogin={this.handleLogin} />
</Route>
<Route exact path="/recipes">
<RecipesPage activeUser={activeUser} addRecipe={this.addRecipe} allRecipes={allRecipes} handleLogout={this.handleLogout} userRecipes={activeUserRecipes} />
</Route>
<Route path="/recipes/:id">
<RecipeDetailsPage activeUser={activeUser} addRecipe={this.addRecipe} allRecipes={allRecipes} handleLogout={this.handleLogout} userRecipes={activeUserRecipes} />
</Route>
<Route path="/dinner">
<PlannedDinnerPage activeUser={activeUser} addRecipe={this.addRecipe} allRecipes={activeUserRecipes} handleLogout={this.handleLogout} />
</Route>
<Route path="/shopping">
<ShoppingListPage activeUser={activeUser} addRecipe={this.addRecipe} allRecipes={allRecipes} handleLogout={this.handleLogout} userRecipes={activeUserRecipes} />
</Route>
</Switch>
);
}
}
export default App;
RecipesPage.js import Реагировать из'act 'import RecipesNavbar из' ../components/RecipesNavbar 'import {Container, Row, Col, Button, Modal, Form} из'act-bootstrap' import {Перенаправление} из'act-router-dom 'импортирует RecipeCard из' ../components/RecipeCard'
class RecipesPage extends React.Component {
constructor(props) {
super(props);
this.state = {
navigateToRecipeId: null,
showModal: false
}
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
this.createRecipe = this.createRecipe.bind(this);
this.openRecipeDetails = this.openRecipeDetails.bind(this);
this.nameInput = React.createRef();
this.descInput = React.createRef();
this.imgInput = React.createRef();
}
openRecipeDetails() {
let navigateToRecipeId = this.props.recipeData.id;
this.setState({ navigateToRecipeId });
}
openModal() {
this.setState({ showModal: true })
}
closeModal() {
this.setState({ showModal: false })
}
createRecipe() {
const newRecipe = {
name: this.nameInput.current.value,
desc: this.descInput.current.value,
img: this.imgInput.current.value,
}
this.props.addRecipe(newRecipe);
this.closeModal();
}
/*
activeUser={activeUser}
addRecipe={this.addRecipe}
allRecipes={allRecipes}
handleLogout={this.handleLogout}
recipe={recipe}
recipeId={recipeId}
userRecipes={activeUserRecipes}
*/
render() {
const { activeUser, handleLogout, allRecipes } = this.props;
const { recipeId, userRecipes } = this.props;
const { showModal } = this.state;
if (!activeUser) {
return <Redirect to="/" />
}
const recipesCards = allRecipes.map(recipe =>
<Col key={recipe.id} lg="3" md="6">
<RecipeCard activeUser={activeUser} recipe={recipe} recipeData={recipe} />
</Col>
);
return (
<div>
<RecipesNavbar activeUser={activeUser} handleLogout={handleLogout} />
<Container>
<div className="recipes-header">
<h1>{activeUser.fname}'s Recipes</h1>
<Button variant="primary" onClick={this.openModal}>New Recipe</Button>
</div>
<Row>
{recipesCards}
</Row>
</Container>
<Modal show={showModal} onHide={this.closeModal} size="lg">
<Modal.Header closeButton>
<Modal.Title>New Recipe</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group as={Row} controlId="formHorizontalEmail">
<Form.Label column sm={2}>
Name
</Form.Label>
<Col sm={10}>
<Form.Control ref={this.nameInput} type="text" placeholder="Recipe name" />
</Col>
</Form.Group>
<Form.Group as={Row} controlId="formHorizontalPassword">
<Form.Label column sm={2}>
Description
</Form.Label>
<Col sm={10}>
<Form.Control ref={this.descInput} type="text" placeholder="Recipe description" />
</Col>
</Form.Group>
<Form.Group as={Row} controlId="formHorizontalPassword">
<Form.Label column sm={2}>
Image URL
</Form.Label>
<Col sm={10}>
<Form.Control ref={this.imgInput} type="text" placeholder="Recipe image URL" />
</Col>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={this.closeModal}>
Close
</Button>
<Button variant="primary" onClick={this.createRecipe}>
Create Recipe
</Button>
</Modal.Footer>
</Modal>
</div>
);
}
}
export default RecipesPage;
RecipeCard.js
import React from 'react'
import { Card } from 'react-bootstrap'
import { Redirect } from 'react-router-dom'
class RecipeCard extends React.Component {
constructor(props) {
super(props);
this.state = {
navigateToRecipeId: null,
recipeId: null,
recipe: null,
recipeData: null,
}
this.openRecipeDetails = this.openRecipeDetails.bind(this);
}
openRecipeDetails() {
console.log("openRecipeDetails - RecipeId: " + this.props.recipe.id);
let { navigateToRecipeId, recipe, recipeData } = this.state;
navigateToRecipeId = this.props.recipe.id;
recipe = this.props.recipe;
recipeData = this.props.recipe;
// this.state.recipeDetails = from data files / database;
this.setState({ navigateToRecipeId, recipeData });
}
render() {
const { activeUser, recipe, activeUserRecipes, recipeData } = this.props;
const { navigateToRecipeId } = this.state;
/*
activeUser={activeUser}
addRecipe={this.addRecipe}
allRecipes={allRecipes}
handleLogout={this.handleLogout}
recipe={recipe}
recipeId={recipeId}
userRecipes={activeUserRecipes}
*/
if (this.state.navigateToRecipeId != null) {
const { navigateToRecipeId } = this.state;
return (
<Redirect to={'/recipes/' + this.state.navigateToRecipeId} activeUser={activeUser} recipe={recipeData} recipeData={recipeData} recipeId={navigateToRecipeId} recipe={recipe} userRecipes={activeUserRecipes} />
);
} else {
return (
<Card className="recipe" >
<Card.Img onClick={this.openRecipeDetails} variant="top" src={recipeData.img} />
<Card.Body>
<Card.Title>{recipeData.name}</Card.Title>
<Card.Subtitle>{recipeData.desc}</Card.Subtitle>
<Card.Text>Cooking Time: {recipeData.duration} min</Card.Text>
</Card.Body>
</Card>
);
}
}
}
export default RecipeCard;
RecipeDetailsPage.js
import React from 'react'
import { Jumbotron, Button, Container } from 'react-bootstrap'
import RecipesNavbar from '../components/RecipesNavbar';
class RecipeDetailsPage extends React.Component {
constructor(props) {
super(props);
this.state = {
navigateToRecipeId: null,
recipeId: null,
recipe: null,
recipeData: null,
}
}
/*
activeUser={activeUser}
allRecipes={allRecipes}
userRecipes={activeUserRecipes}
recipeId={recipeId}
handleLogout={this.handleLogout}
addRecipe={this.addRecipe}
*/
componentDidMount() {
console.log("RecipeDetailsPage.componentDidMount() -- recipeId = ?");
console.log("RecipeDetailsPage.componentDidMount() -- recipeId: " + this.props.recipe.id);
let recipeId = this.props.match.params.id;
}
render() {
const { activeUser, handleLogout } = this.props;
return (
<div>
<RecipesNavbar activeUser={activeUser} handleLogout={handleLogout} />
<Jumbotron>
<Container>
<h1 className="display-3">Show Details of Selected Recipe</h1>
<div>Name: < R e c i p e N a m e ></div>
<div>Description: < R e c i p e D e s c r i p t i o n ></div>
<div>Duration: < (nnn) min ></div>
<div>Kitchen: < K i t c h e n i t B e l o n g s T o ></div>
<div>Type: < R e c i p e T y p e ></div>
</Container>
</Jumbotron>
</div>
);
}
}
export default RecipeDetailsPage;
В RecipeCard.js
в Redirect
я вижу значения свойств, которые я хочу отправить, но в RecipeDetailsPage.js
в constructor
сразу после вызова super(props)
Я не вижу отправленных мною свойствв перенаправлении только те, которые есть в App.js
in Route
компонента RecipeDetailsPage
.
Я ищу подсказку в google, но все, что я нашел до сих пор, это о свойствах seding сRoute
(я все еще ищу).
Что я делаюнеправильно? Что мне не хватает? Правильна ли моя практика или я должен делать это по-другому?