Problème Projet React

Par brun34, il y a 5 ans


Bonjour,

Je rencontre un petit problème avec mon code.

Ce que je fais

je souhaite faire le Update de la formation React
mon code RecipeForm.jsx

import React, {useCallback, useState} from 'react' import {Field} from "../../UI/Field"; import {Loader} from "../../UI/Loader"; import PropTypes from "prop-types" import {Button} from "../../UI/Button"; import {Trash} from "../../UI/Icon"; import {ApiErrors} from "../../utils/Api"; export function CreateRecipeForm({ingredients, onSubmit}) { return <RecipeForm ingredients={ingredients} onSubmit={onSubmit} button="Ajouter"/> } export function EditRecipeForm({ingredients, onSubmit, recipe}) { return <RecipeForm ingredients={ingredients} onSubmit={onSubmit} recipe={recipe} button="Editer"/> } function RecipeForm({ingredients, onSubmit, recipe = {}, button}) { const { ingredients: recipeIngredients, addIngredients, updateQuantity, deleteIngredients, resetIngredients } = useIngredients(recipe.ingredients) const [errors, setErrors] = useState({}) const filteredIngredients = (ingredients || []).filter(ingredient =>{ return !recipeIngredients.some(i=> i.id === ingredient.id) }) const handleSubmit = async function (e) { e.preventDefault() const form = e.target const data = Object.fromEntries(new FormData(form)) data.ingredients= recipeIngredients setErrors({}) try{ await onSubmit(data) form.reset() resetIngredients() }catch (e) { if (e instanceof ApiErrors){ setErrors(e.errorsPerField) }else { throw e } } } return <form className="row" onSubmit={handleSubmit}> <div className="col-md-6"> <Field name="title" error={errors.title} required defaultValue={recipe.title} >Titre</Field> <Field name="short" type="textarea" error={errors.short} defaultValue={recipe.short} required >Description courte</Field> <Field name="content" type="textarea" error={errors.content} defaultValue={recipe.content} required >Description</Field> </div> <div className="col-md-6"> <h5>Ingrédients</h5> {recipeIngredients.map(i => <IngredientRow ingredient={i} key={i.id} onChange={updateQuantity} onDelete={deleteIngredients} />)} {ingredients ? <Select ingredients={filteredIngredients} onChange={addIngredients}/> : <Loader />} </div> <div className="col-md-12 mt-3"> <Button type="submit">{button}</Button> </div> </form> } RecipeForm.propTypes = { ingredients : PropTypes.array, } function useIngredients(initial) { const [ingredients, setIngredients] = useState(initial || []) return { ingredients: ingredients, addIngredients: useCallback(function (ingredient){ setIngredients(state => [...state, ingredient]) }, []), updateQuantity: useCallback(function (ingredient, quantity){ setIngredients(state => state.map(i => i === ingredient ? {...i, quantity } : i )) },[]), deleteIngredients: useCallback(function (ingredient) { setIngredients(state => state.filter(i => i !== ingredient)) }, []), resetIngredients: useCallback(function () { setIngredients([]) },[]) } } function IngredientRow({ ingredient, onChange, onDelete }) { const handleChange =function (e) { onChange(ingredient, e.target.value) } return <div className="d-flex mb-3 align-items-center"> <div className="mr-2">{ingredient.title}</div> <Field className="mb-0" defaultValue={ingredient.quantity} placeholder="quantité" onChange={handleChange} required type="number"/> <div className="ml-2">{ingredient.unit}</div> <Button type="danger" onClick={ ()=> onDelete(ingredient)}><Trash /></Button> </div> } /** *Select un ingrédient * * @param {{ingredients: array}} state * **/ function Select({ ingredients, onChange}){ const handleChange = function (e) { onChange(ingredients[parseInt(e.target.value, 10)]) } return <select className="form-control" onChange={handleChange}> <option>Sélectionner un ingrédients</option> {ingredients.map( (i, k) => <option key={i.id} value={k}> {i.title} </option> )} </select> }

et mon Recipe.jsx

import React from 'react' import PropTypes from 'prop-types' import {Loader} from "../../UI/Loader"; import {Modal} from "../../UI/Modal"; import {useToggle} from "../../hooks"; import {EditRecipeForm} from "./RecipeForm"; import {Button} from "../../UI/Button"; export function Recipe({ recipe, onClose, onEdit, ingredients, onDelete, onUpdate }) { return( <Modal title={recipe.title} onClose={onClose}> {!recipe.ingredients ? <Loader /> : <RecipeDetail recipe={recipe} onEdit={onEdit} onUpdate={onUpdate} ingredients={ingredients} /> } <Button type="danger" onClick={() => onDelete(recipe)}>Supprimer</Button> </Modal> ) } function RecipeDetail({ recipe, ingredients , onEdit, onUpdate }){ const [editMode, toggleEditMode] = useToggle(false) const htmlContent = {__html: recipe.content.split("\n").join('<br/>')} const handleUpdate = async function (data) { await onUpdate(recipe,data) toggleEditMode() } const handleEditMode = function () { toggleEditMode() onEdit() } return editMode ? <EditRecipeForm recipe={recipe} ingredients={ingredients} onSubmit={handleUpdate} /> : <> <div dangerouslySetInnerHTML={htmlContent}> </div> <h4 className="mt-4">Ingrédients</h4> <ul> {recipe.ingredients.map(i => <IngredientRow ingredient={i} key={i.id}/>)} </ul> <Button onClick={handleEditMode}>Editer</Button> </> } function IngredientRow({ ingredient }){ return <li> <strong> {ingredient.quantity} {ingredient.unit}</strong> {ingredient.title} </li> } Recipe.propTypes = { recipe: PropTypes.object.isRequired, }

Ainsi que Site.jsx

import React, {useState, useEffect} from 'react' import {Ingredients} from "./Ingredients/Ingredients"; import {useIngredients} from "../hooks/ingredients"; import {Recipes} from "./Recipes/Recipes"; import {useRecipes} from "../hooks/recipes"; import {Recipe} from './Recipes/Recipe' import {useToggle} from "../hooks"; import {CreateRecipeForm} from "./Recipes/RecipeForm"; import {Modal} from "../UI/Modal"; export function Site() { const [page, setPage] = useState('recipes') const [add, toggleAdd] = useToggle(false) const { ingredients, fetchIngredients, deleteIngredient, updateIngredient, createIngredient }= useIngredients() const { recipes, recipe, fetchRecipes, fetchRecipe, deselectRecipe, createRecipe, updateRecipe, deleteRecipe } = useRecipes() let content = null if (page === 'ingredients'){ content = <Ingredients ingredients={ingredients} onDelete={deleteIngredient} onUpdate={updateIngredient} onCreate={createIngredient} /> }else if (page === 'recipes'){ content = <Recipes recipes={recipes} onClick={fetchRecipe}/> } useEffect(function () { if (page === 'ingredients' || add === true){ fetchIngredients() } if (page === 'recipes'){ fetchRecipes() } }, [page, fetchIngredients,fetchRecipes, add]) return <> <NavBar currentPage={page} onClick={setPage} onButtonClick={toggleAdd}/> <div className="container"> {recipe ? <Recipe recipe={recipe} ingredients={ingredients} onClose={deselectRecipe} onEdit={fetchIngredients} onUpdate={updateRecipe} onDelete={deleteRecipe} /> : null} {add && <Modal title="Créer une recette" onClose={toggleAdd}> <CreateRecipeForm ingredients={ingredients} onSubmit={createRecipe}/> </Modal>} {content} </div> </> } function NavBar({currentPage, onClick, onButtonClick }) { const navClass = function (page) { let className = 'nav-item' if (page === currentPage){ className=' active' } return className } return <nav className="navbar navbar-expand-sm navbar-dark bg-primary mb-4"> <a href="#recipes" className="navbar-brand " onClick={()=> onClick('recipes')}>recettes</a> <ul className="navbar-nav mr-auto"> <li className={navClass('recipes')}> <a href="#recipes" className="nav-link" onClick={()=> onClick('recipes')}>Recettes</a> </li> <li className={navClass('ingredients')}> <a href="#ingredients" className="nav-link" onClick={()=> onClick('ingredients')}>Ingrédients</a> </li> </ul> <button onClick={onButtonClick} className="btn btn-outline-light"> Ajouter un nouvelle reccette </button> </nav> }

Ce que je veux

je veux pouvoir revenir sur la page sans problème

Ce que j'obtiens

j'obtient cette erreur :"TypeError: state.recipes.find is not a function
useRecipes
C:/Users/front/src/hooks/recipes.js:37

34 | recipeId: null
35 | })
36 |

37 | const recipe = state.recipes ? state.recipes.find(r => r.id === state.recipeId) : null
| ^ 38 |
39 | return {
40 | recipes: state.recipes,
"

mais tout les changements se font, la recette est bien changée mais cette erreur vient quand même

HELP ME

Aucune réponse