React-router Route not rendering component - javascript

I'm trying to use react router in the following code, and render the RecipeCardDetail component. URL changes but nothing renders. It just renders when I click URL and press enter. I'm trying to show recipeId (URL Parameter) in the RecipeCardDetail component. I would like some help if possible.
Below my components.
App.js
import React, { useEffect, useState } from 'react';
import './App.css';
import RecipeCard from './components/RecipeCard/RecipeCard';
import RecipeCardDetail from "./components/RecipeCardDetail/RecipeCardDetail"
import Form from './components/Form/Form';
import axios from 'axios';
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
function App() {
const [recipes, setRecipes] = useState([])
const [filter, setFilter] = useState("")
const [query, setQuery] = useState("")
useEffect(() => {
getRecipe()
}, [query])
const getRecipe = () => {
const key = process.env.REACT_APP_RECIPE_SEARCH_APP_API_KEY
const id = process.env.REACT_APP_RECIPE_SEARCH_APP_ID
axios.get(`https://api.edamam.com/api/recipes/v2?type=public&q=${query}&app_id=${id}&app_key=${key}`)
.then(response => {
console.log(response.data.hits)
setRecipes(response.data.hits)
})
.catch(error => {
console.log(error)
})
}
return (
<Router>
<div className="App">
<div className="container">
<Form setFilter={setFilter} setQuery={setQuery} filter={filter} />
<div className="row">
<Switch>
<Route exact path="/" >
{recipes.map((item, id) => {
return <RecipeCard key={id} img={item.recipe.image} title={item.recipe.label} ingredients={item.recipe.ingredientLines} recipeId={id} />
})}
</Route>
<Route path="/recipe-card-detail/:recipeId" >
<RecipeCardDetail />
</Route>
</Switch>
</div>
</div>
</div>
</Router>
);
}
export default App;
RecipeCard.js
import React from 'react'
import "./style.css"
import "../../../node_modules/bootstrap/dist/css/bootstrap.min.css"
import { BrowserRouter as Router, Link } from "react-router-dom"
function RecipeCard( { img, title, ingredients, recipeId } ) {
return (
<Router>
<div className="col-xl-4 col-md-6 col-s-12">
<div className="card mt-5" style={{ width: "24rem" }}>
<img src={img} className="card-img-top" alt="img" />
<div className="card-body">
<h3 className="text align">{title}</h3>
<ul className="card-text">
{ingredients.map((item, id) => {
return <li key={id} >{item}</li>
})}
</ul>
<Link to={`/recipe-card-detail/${recipeId}`}>Details</Link>
</div>
</div>
</div>
</Router>
)
}
export default RecipeCard

Try changing the order in which you are defining the routes.
<Switch>
<Route path="/recipe-card-detail/:recipeId" >
<RecipeCardDetail />
</Route>
<Route exact path="/" >
{recipes.map((item, id) => {
return <RecipeCard key={id} img={item.recipe.image} title={item.recipe.label} ingredients={item.recipe.ingredientLines} recipeId={id} />
})}
</Route>
</Switch>

Related

useParam is not working in react router Dom v6?

I am trying to pass a parameter to my other component which is productDetail component but when I am trying to access that parameter value using useParam it doesn't seems to work:
App:
import React from "react";
import { Route, Routes } from "react-router-dom";
import MainHeader from "./components/MainHeader.jsx";
import Product from "./pages/Product.jsx";
import ProductDetails from "./pages/ProductDetails.jsx";
import Welcome from "./pages/Welcome.jsx";
const App = () => {
return (
<div style={{ textAlign: "center" }}>
<header>
<MainHeader />
</header>
<Routes>
<Route path="/welcome" element={<Welcome />} />
<Route path="/product" element={<Product />} />
<Route path="/products/:productId" element={<ProductDetails />} />
</Routes>
</div>
);
};
export default App;
ProductDetailes:
import React from "react";
import { useParams } from "react-router-dom";
const ProductDetails = () => {
const params = useParams;
console.log(params.productId);
return (
<div>
<h1>Product Detail</h1>
<p>{params.productId}</p>
</div>
);
};
export default ProductDetails;
The useParams hook is a function and actually needs to be invoked in order to have any effect.
Example:
const ProductDetails = () => {
const { productId } = useParams();
useEffect(() => {
console.log({ productId });
}, [productId]);
return (
<div>
<h1>Product Detail</h1>
<p>{productId}</p>
</div>
);
};

React : How to make my SearchBar render in another Page?

I have 2 pages both are childrens from App.
_ NavbarComp.js
_ Home.js
Right now I have a functionnal SearchBar in my Home, I'd like to pass the values between NavbarComp & Home.
When I search from my NavbarComp, I'd like to have a render only on the Home page.
This is what it looks like so far.
I now need to remove my input button from Home, and pass the values between both pages Navbar & Home.
I dont think I can use props there, tho.. looking for solutions !
NavbarComp.js
import { Layout } from "antd";
import { Link, useHistory } from "react-router-dom";
import Cookies from "js-cookie";
import { useDispatch } from "react-redux";
import { logout } from "redux/auth/authActions";
import { Nav, Navbar, NavDropdown, Form, FormControl, Button, Row, Col, Container } from "react-bootstrap";
const { Header } = Layout;
export const NavbarComp = ({input, setInput}) => {
const history = useHistory();
const cookie = Cookies.get('token');
const dispatch = useDispatch();
const logMeOut = (e) => {
e.preventDefault();
dispatch(logout());
history.push('/');
}
return (
<>
<Navbar bg="light" expand="lg">
<Form className="d-flex">
<FormControl
type="search"
placeholder="Search"
className="mr-2"
aria-label="Search"
input={input}
/>
</Navar>
</>
)
}
Home.js
import React from 'react';
import { Link } from "react-router-dom";
import { useSelector } from 'react-redux';
import { v4 as uuid_v4 } from "uuid";
export const Home = () => {
const connected = useSelector(state => state.auth.user)
const [input, setInput] = React.useState('');
const [flats, setFlats] = React.useState([]);
const [flatsDefault, setFlatsDefault] = React.useState([]);
React.useEffect(() => {
getListing('real_estates')
}, [])
const getListing = async (url) => {
const config = {
method: 'GET',
};
const response = await fetch(`${process.env.REACT_APP_API_URL}/${url}`, config);
const data = await response.json();
setFlats(data)
setFlatsDefault(data)
};
const updateInput = async (input) => {
const filtered = flatsDefault.filter(flat => {
return flat.title.toLowerCase().includes(input.toLowerCase())
})
setInput(input);
setFlats(filtered);
}
return (
<>
<input
type='text'
input={input}
placeholder={"Search for properties"}
onChange={(e) => updateInput(e.target.value)}
/>
<div className="home-header">
<div className="bg-img-desc">
<h1>List of real estates</h1>
</div>
</div>
<div className="container" style={{ padding: '0 3.5rem' }}>
<ul className="row">
{flats ? (
flats.map(flat => (
<li className="col-12 col-sm-6 col-md-4 col-lg-3 mb-4" key={uuid_v4()}>
<div className="card h-100">
{ flat.images_url && <img src={`${process.env.REACT_APP_API_URL}${flat.images_url[0]}`} className="card-img-top" alt=""/> }
<div className="card-body">
<h5>{flat.title}</h5>
<p>Price : {flat.price} €</p>
<p>location : {flat.location}</p>
{connected && <Link to={`/real_estates/${flat.id}`} className="btn btn-primary">Details</Link>}
</div>
</div>
</li>
))
) : (
<h2>Loading...</h2>
)}
</ul>
</div>
</>)
}
App.js
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { Layout } from 'antd';
import { NavbarComp } from "components/NavbarComp";
import { Home } from "pages/Home";
import Realestate from "pages/Realestate";
import NewRealestate from "pages/NewRealestate";
import { Other } from "pages/Other";
import { Login } from "pages/Login";
import { Register } from "pages/Register";
import Profile from "pages/Profile";
import { useDispatch, useSelector } from 'react-redux';
import { getUser } from 'redux/auth/authActions';
import Cookies from 'js-cookie';
function App() {
const dispatch = useDispatch();
const user = useSelector(state => state.auth.user);
React.useEffect(() => {
dispatch(getUser(Cookies.get('id')))
console.log(user)
}, [])
return (
<Layout className="layout" style={{ backgroundColor: 'transparent' }}>
<Router>
<NavbarComp />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route exact path="/real_estates/:id">
<Realestate />
</Route>
<Route path="/new_real_estate">
<NewRealestate />
</Route>
<Route path="/other">
<Other />
</Route>
<Route exact path="/login" >
<Login />
</Route>
<Route exact path="/register" >
<Register />
</Route>
<Route exact path="/profile" >
<Profile user={user} />
</Route>
</Switch>
</Router>
</Layout>
);
}
export default App;
I can see three ways that you can implement to resolve this.
The first one is creating a context, so your state is going to be share through all your app. So when you change it inside your NavbarComp you will be able to get this value in another component.
The second one is similar to context but using redux. I saw that you are using redux in your project, you can share those values through redux.
The other way is to create a useState() inside your app component and pass it as props to your NavbarComp and your home. So this state will be shared between those two.
function App() {
const dispatch = useDispatch();
const user = useSelector(state => state.auth.user);
const [value, setValue] = useState()
React.useEffect(() => {
dispatch(getUser(Cookies.get('id')))
console.log(user)
}, [])
return (
<Layout className="layout" style={{ backgroundColor: 'transparent' }}>
<Router>
<NavbarComp value={value} setValue={setValue}/>
<Switch>
<Route exact path="/">
<Home value={value} setValue={setValue}/>
</Route>
<Route exact path="/real_estates/:id">
<Realestate />
</Route>
<Route path="/new_real_estate">
<NewRealestate />
</Route>
<Route path="/other">
<Other />
</Route>
<Route exact path="/login" >
<Login />
</Route>
<Route exact path="/register" >
<Register />
</Route>
<Route exact path="/profile" >
<Profile user={user} />
</Route>
</Switch>
</Router>
</Layout>
);
}
export default App;

React cannot read property '' of undefined

please im having issue rendering dynamic data in my react ProductScreen.js
Note,... the data rendered well in Product.js but same data isnt render in the ProductScreen.js because the ProductScreen.js link is rendered via the "id"
Thanks
App.js
import './App.css';
import { useState, useEffect } from 'react';
import { BrowserRouter as Router, Switch, Route} from 'react-router-dom';
//Screens
import HomeScreen from './screens/HomeScreen';
import ProductScreen from './screens/ProductScreen';
import CartScreen from './screens/CartScreen';
//components
import Navbar from './components/Navbar'
import Backdrop from './components/Backdrop'
import SideDrawer from './components/SideDrawer'
import AddProductScreen from './screens/AddProductScreen';
import data from './data'
function App() {
const { products } = data;
const [sideToggle, setSideToggle] = useState(false)
const [cartItems, setCartItem] = useState([])
const onAdd = (product) =>{
const exist = cartItems.find(item => item.id === product.id)
if (exist) {
setCartItem(cartItems.map(item => item.id === product.id ? {...exist, qty: exist.qty + 1} : item ))
} else{
setCartItem([...cartItems, {...product, qty: 1}])
}
}
const onRemove =(product) =>{
}
return (
<Router>
<Navbar countCartItems={cartItems.length} click={() => setSideToggle(true)}/>
<Backdrop show={sideToggle} click={() => setSideToggle(false)} />
<SideDrawer show={sideToggle} click={() => setSideToggle(false)} />
{/* <HomeScreen products={ products } onAdd={ onAdd }/> */}
{/* <CartScreen onRemove={onRemove} onAdd={onAdd} cartItems={cartItems}/> */}
{products.map(product => (
<h1></h1>
))}
<main>
<Switch>
<Route exact path="/" > <HomeScreen products={ products } onAdd={ onAdd }/> </Route>
<Route exact path="/cart" > <CartScreen cartItems={cartItems} onRemove={ onRemove } onAdd={ onAdd }/>
</Route>
<Route exact path="/product/:id" > <ProductScreen cartItems={cartItems} onAdd={ onAdd }/> products={products} </Route>
<Route exact path="/add" component={AddProductScreen} />
</Switch>
</main>
</Router>
);
}
export default App;
HomeScreen.js
import './HomeScreen.css';
import Product from '../components/Product'
import { useEffect } from 'react';
// import data from '../data'
const HomeScreen = ({ onAdd, products }) => {
// const { products } = data;
return (
<div className="homescreen">
<h1 className="homescreen_title">Latest Products</h1>
<div className="homescreen_products">
{products.map(product => (
<Product key={ product.id } product={ product } onAdd={ onAdd }/>
)) }
</div>
</div>
)
}
export default HomeScreen
ProductScreen.js
import './ProductScreen.css';
const ProductScreen = ({ products }) => {
return (
<div className="productscreen">
<div className="productscreen__left">
<div className="left__image">
<img className="small" src={products.image} alt={product.name} />
</div>
<div className="left__info">
<p className="left__name">{products.name}</p>
<p >${products.price}</p>
<p >${products.descrption}</p>
</div>
</div>
)
}
export default ProductScreen
Product.js
import React from 'react'
import { Link } from 'react-router-dom'
const Product = ({ product, onAdd }) => {
return (
<div>
<img className="small" src={product.image} alt={product.name} />
<h3>{product.name}</h3>
<div>${product.price}</div>
<div>
<button onClick={()=> onAdd(product)}> Add To Cart</button>
<button > <Link to={`/product/${product.id}`}>Features</Link></button>
</div>
</div>
)
}
export default Product
The problem is that you are sending the items to ProductsScreen as cartItems <ProductScreen cartItems = {cartItems} onAdd = {onAdd} /> but you are calling the product property that does not exist const ProductScreen = ({product}) => {}

React router renders blank page using exact on all routes

I have a problem with one of my components in which react router returns a blank page when accessing it. It only happens in one component and I do not know why.The component that has the problem is the EditPost component.
App.js
This is where all the routes are.
import "./App.css";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import Home from "./components/Home.js";
import Signup from "./components/signup/Signup";
import Login from "./components/Login/Login";
import Dashboard from "./components/Dashboard/Dashboard";
import PrivateRoute from "./components/common/PrivateRoutes";
import { Provider } from "react-redux";
import Store from "./Store";
import { Provider as AlertProvider } from "react-alert";
import AlertTemplate from "react-alert-template-basic";
import { loadUser } from "./actions/auth";
import { useEffect } from "react";
import PostPage from "./components/PostPage/PostPage";
import EditPost from "./components/EditPost/EditPost";
// Alert options
const alertOptions = {
timeout: 3000,
};
function App() {
useEffect(() => {
Store.dispatch(loadUser());
}, []);
return (
<div className="App">
<Provider store={Store}>
<AlertProvider template={AlertTemplate} {...alertOptions}>
<Router>
<Switch>
<Route exact path="/post-edit/:id" component={EditPost} />
<Route exact path="/signup" component={Signup} />
<Route exact path="/login" component={Login} />
<PrivateRoute exact path="/dashboard" component={Dashboard} />
<Route exact path="/" component={Home} />
<Route exact path="/post/:id" component={PostPage} />
</Switch>
</Router>
</AlertProvider>
</Provider>
</div>
);
}
export default App;
EditPost.js
This is the component that does not render
import React, { useState } from "react";
import { Form, Button } from "react-bootstrap";
import { connect } from "react-redux";
import { updatePost } from "../../actions/posts";
const EditPost = (props) => {
console.log(props);
const [title, setTitle] = useState(props.location.postData.title);
const [description, setDescription] = useState(
props.location.postData.description
);
const [body, setBody] = useState(props.location.postData.body);
const titleChange = (e) => {
setTitle(e.target.value);
};
const bodyChange = (e) => {
setBody(e.target.value);
};
const desChange = (e) => {
setDescription(e.target.value);
};
const addClick = (e) => {
e.preventDefault();
const post = { title, body, description };
props.updatePost(post);
};
return (
<div className="mt-4">
<h1>Edit Post</h1>
<Form>
<Form.Group>
<Form.Label>Post Title</Form.Label>
<Form.Control onChange={titleChange} type="text" />
</Form.Group>
<Form.Group>
<Form.Label>Short Description</Form.Label>
<Form.Control onChange={desChange} type="text" />
</Form.Group>
<Form.Group>
<Form.Label>Body</Form.Label>
<Form.Control onChange={bodyChange} as="textarea" rows={3} />
</Form.Group>
<Button onClick={addClick} variant="primary" type="submit">
Edit
</Button>
</Form>
</div>
);
};
const mapDispatchToProps = (dispatch) => {
return {
updatePost: (id, post) => dispatch(updatePost(id, post)),
};
};
export default connect(null, mapDispatchToProps)(EditPost);
Post.js
In this component is the link to the EditPost component.
import React from "react";
import { Card } from "react-bootstrap";
import dateFormat from "dateformat";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
const Post = (props) => {
return (
<Card>
<Card.Body>
<Link to={`/post/${props.id}`}>
<Card.Title>{props.title}</Card.Title>
</Link>
<Card.Text>{props.description}</Card.Text>
</Card.Body>
<Card.Footer>
<div className="d-flex justify-content-between">
<small className="text-muted">
{dateFormat(props.created, "mmmm dS, yyyy")}
</small>
{props.postUser === props.user ? (
<Link to={`/edit-post/${props.id}`}>
<i className="fas fa-edit" style={{ color: "grey" }}></i>
</Link>
) : null}
</div>
</Card.Footer>
</Card>
);
};
const mapStateToProps = (state) => {
if (state.auth.isAuthenticated) {
return {
user: state.auth.user.username,
};
} else {
return {};
}
};
export default connect(mapStateToProps)(Post);
Right now I am just trying to get the component rendered, then I will worry about the props. Thanks in advance.
Your link is /edit-post/${props.id}.
Your matched path is /post-edit/:id.
edit-post and post-edit are not the same thing 😉
I would recommend adding a NoMatch block at the end of your Switch. It'll help you to diagnose these problems faster.
<Route>
<NoMatch />
</Route>

Getting error while redirect to the home page in react

I was trying to restrict logged in user to access login page using following code
import React, { useEffect, useState } from "react"; import { Route }
from "react-router-dom"; import { Redirect } from "react-router-dom";
const UserLayoutRoute = ({ component: Component, ...rest }) => {
const [loggedIn, setLoggedIn] = useState(null); useEffect(() => {
if (localStorage.getItem("cachedValue") !== null) {
setLoggedIn(true);
} }, []); return loggedIn ? (
<Route
{...rest}
render={matchProps => (
<div className="App">
<section className="user-page">
<div className="">
<div className="">
<Component {...matchProps} />
</div>
</div>
</section>
</div>
)}
/> ) : (
<Redirect to="/" /> ); };
export default UserLayoutRoute;
With this code page keep on loading and its not rendering anything.
I also posted this issue in GitHub https://github.com/facebook/react/issues/17514
I think that maybe you can try other approach like this
import React from 'react';
import PropTypes from 'prop-types';
import { Route, Redirect } from 'react-router-dom';
const PrivateRouteComponent = ({ component: Component, isAuth, ...rest }) => (
<Route
{...rest}
render={props => (
isAuth
? <Component {...props} />
: <Redirect to="/login" />
)}
/>
);
PrivateRouteComponent.propTypes = {
component: PropTypes.any.isRequired,
isAuth: PropTypes.bool.isRequired,
};
export default PrivateRouteComponent;
And in the case the routes
<Switch>
<PrivateRouteComponent exact path="/" component={**ComponentName**} isAuth={isAuth} />
</Switch>
For the case that the isAuth props maybe you can change that for your condition

Categories

Resources