-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Kyle Zarazan
committed
Nov 19, 2024
1 parent
1202754
commit 42727c1
Showing
9 changed files
with
184 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import React, { useState, useEffect } from 'react'; | ||
|
||
interface Food { | ||
id: number; | ||
name: string; | ||
created_at: string; | ||
modified_at: string; | ||
} | ||
|
||
const FetchDataComponent: React.FC = () => { | ||
const [foods, setFoods] = useState<Food[]>([]); | ||
const [loading, setLoading] = useState<boolean>(true); | ||
const [error, setError] = useState<string | null>(null); | ||
|
||
// Fetch data when the component mounts | ||
useEffect(() => { | ||
const fetchData = async () => { | ||
try { | ||
const response = await fetch('http://localhost:3000/api/foods'); | ||
if (!response.ok) { | ||
throw new Error('Failed to fetch data'); | ||
} | ||
const result: Food[] = await response.json(); | ||
setFoods(result); // Set the fetched data to the state | ||
setLoading(false); // Data loaded, set loading to false | ||
} catch (err: any) { | ||
setError(err.message); // If error occurs, set the error message | ||
setLoading(false); // Stop loading in case of error | ||
} | ||
}; | ||
|
||
fetchData(); | ||
}, []); // Empty dependency array to run only once on mount | ||
|
||
if (loading) { | ||
return <div>Loading...</div>; | ||
} | ||
|
||
if (error) { | ||
return <div>Error: {error}</div>; | ||
} | ||
|
||
return ( | ||
<div> | ||
<h2>Fetched Data:</h2> | ||
<ul> | ||
{foods.map((item) => ( | ||
<li key={item.id}> | ||
{item.id}: {item.name} | ||
{item.created_at} | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
); | ||
}; | ||
|
||
export default FetchDataComponent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,48 @@ | ||
import React, { useState, useEffect } from 'react'; | ||
import React from 'react'; | ||
import { useEffect } from 'react' | ||
import { useAppDispatch, useAppSelector } from '../store/hooks' | ||
import { fetchRecipes } from '../store/recipesSlice' | ||
|
||
interface Recipe { | ||
id: number; | ||
name: string; | ||
created_at: string; | ||
modified_at: string; | ||
} | ||
|
||
const FetchDataComponent: React.FC = () => { | ||
const [recipes, setRecipes] = useState<Recipe[]>([]); | ||
const [loading, setLoading] = useState<boolean>(true); | ||
const [error, setError] = useState<string | null>(null); | ||
const RecipeTable: React.FC = () => { | ||
const dispatch = useAppDispatch() | ||
const { items: recipes, status, error } = useAppSelector((state) => state.recipes) | ||
|
||
// Fetch data when the component mounts | ||
useEffect(() => { | ||
const fetchData = async () => { | ||
try { | ||
const response = await fetch('http://localhost:3000/api/recipes'); | ||
if (!response.ok) { | ||
throw new Error('Failed to fetch data'); | ||
} | ||
const result: Recipe[] = await response.json(); | ||
setRecipes(result); // Set the fetched data to the state | ||
setLoading(false); // Data loaded, set loading to false | ||
} catch (err: any) { | ||
setError(err.message); // If error occurs, set the error message | ||
setLoading(false); // Stop loading in case of error | ||
} | ||
}; | ||
dispatch(fetchRecipes()) | ||
}, [dispatch]) | ||
|
||
fetchData(); | ||
}, []); // Empty dependency array to run only once on mount | ||
|
||
if (loading) { | ||
return <div>Loading...</div>; | ||
if (status === 'loading') { | ||
return <div>Loading...</div> | ||
} | ||
|
||
if (error) { | ||
return <div>Error: {error}</div>; | ||
if (status === 'failed') { | ||
return <div>Error: {error}</div> | ||
} | ||
|
||
return ( | ||
<div> | ||
<h2>Fetched Data:</h2> | ||
<ul> | ||
{recipes.map((item) => ( | ||
<li key={item.id}> | ||
{item.id}: {item.name} | ||
{item.created_at} | ||
</li> | ||
))} | ||
</ul> | ||
<table> | ||
<thead> | ||
<tr> | ||
<th>Recipe Name</th> | ||
<th>Ingredients</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{recipes.map((recipe) => ( | ||
<tr key={recipe.id}> | ||
<td>{recipe.name}</td> | ||
<td> | ||
{recipe.ingredients?.map((ingredient) => ( | ||
<span key={ingredient.id}>{ingredient.food_name}</span> | ||
))} | ||
</td> | ||
</tr> | ||
))} | ||
</tbody> | ||
</table> | ||
</div> | ||
); | ||
}; | ||
) | ||
} | ||
|
||
export default FetchDataComponent; | ||
export default RecipeTable |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux' | ||
import type { RootState, AppDispatch } from './store' | ||
|
||
export const useAppDispatch: () => AppDispatch = useDispatch | ||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit' | ||
|
||
export const fetchRecipes = createAsyncThunk( | ||
'recipes/fetchRecipes', | ||
async () => { | ||
const response = await fetch('/api/recipes') | ||
return response.json() | ||
} | ||
) | ||
|
||
interface Ingredient { | ||
id: number; | ||
food_name: string; | ||
measurement: string; | ||
} | ||
|
||
interface Recipe { | ||
id: number; | ||
name: string; | ||
ingredients: Ingredient[]; | ||
} | ||
|
||
interface RecipesState { | ||
items: Recipe[] | ||
status: 'idle' | 'loading' | 'succeeded' | 'failed' | ||
error: string | null | ||
} | ||
|
||
const initialState: RecipesState = { | ||
items: [], | ||
status: 'idle', | ||
error: null | ||
} | ||
|
||
const recipesSlice = createSlice({ | ||
name: 'recipes', | ||
initialState, | ||
reducers: {}, | ||
extraReducers: (builder) => { | ||
builder | ||
.addCase(fetchRecipes.pending, (state) => { | ||
state.status = 'loading' | ||
}) | ||
.addCase(fetchRecipes.fulfilled, (state, action) => { | ||
state.status = 'succeeded' | ||
state.items = action.payload | ||
}) | ||
.addCase(fetchRecipes.rejected, (state, action) => { | ||
state.status = 'failed' | ||
state.error = action.error.message || null | ||
}) | ||
}, | ||
}) | ||
|
||
export default recipesSlice.reducer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { configureStore } from '@reduxjs/toolkit' | ||
import recipesReducer from './recipesSlice' | ||
|
||
export const store = configureStore({ | ||
reducer: { | ||
recipes: recipesReducer, | ||
}, | ||
}) | ||
|
||
export type RootState = ReturnType<typeof store.getState> | ||
export type AppDispatch = typeof store.dispatch |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
class Recipe < ApplicationRecord | ||
has_many :ingredients | ||
|
||
accepts_nested_attributes_for :ingredients | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters