React Router - The Address Bar Is Changing But Not Rendering The Component - javascript

I Am Making A Search Functionality On My Website But Whenever I Type Something And Hit The Search Button The Address ( URL ) Changes But The Component Stays The Same And When I Refresh The Page After That The Component Appears On The Screen.
Here's A Picture Of What I Meant :
URL CHANGES BUT COMPONENT IS SAME
Here's A Picture After The Reload :
Should Be Like This When I Hit The Search
There Was A Solution I Found That Changing From Browser Router To Router Works But That Seems To Give The Following Error :
Uncaught TypeError: Cannot read properties of undefined (reading 'pathname')
App.js
import "./App.css";
import {
BrowserRouter as Router,
Route,
Switch,
Routes,
} from "react-router-dom";
import Header from "./Components/Layouts/Header";
import Footer from "./Components/Layouts/Footer";
import Home from "./Components/Home";
import ProductDetails from "./Components/Product/ProductDetails";
function App() {
return (
<Router>
<div className="App">
<Header />
<div className="container container-fluid">
<Routes>
<Route path="/" element={<Home />} exact />
<Route path="/search/:keyword" element={<Home />} />
<Route path="/product/:id" element={<ProductDetails />} />
</Routes>
</div>
<Footer />
</div>
</Router>
);
}
export default App;
History.js
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
export default history;
Header Component
import React, { Fragment } from "react";
import { Route } from "react-router-dom";
import history from "./history";
import Search from "./Search";
const Header = () => {
return (
<Fragment>
<nav className="navbar row">
<div className="col-12 col-md-3">
<div className="navbar-brand">
<img src="./images/logo.png" />
</div>
</div>
<div className="col-12 col-md-6 mt-2 mt-md-0">
<Search history={history} />
</div>
<div className="col-12 col-md-3 mt-4 mt-md-0 text-center">
<button className="btn" id="login_btn">
Login
</button>
<span id="cart" className="ml-3">
Cart
</span>
<span className="ml-1" id="cart_count">
2
</span>
</div>
</nav>
</Fragment>
);
};
export default Header;
Search Component
import React, { useState } from "react";
const Search = ({ history }) => {
const [keyword, setKeyword] = useState("");
const searchHandler = (e) => {
e.preventDefault();
if (keyword.trim()) {
history.push(`/search/${keyword}`);
} else {
history.push("/");
}
};
return (
<form onSubmit={searchHandler}>
<div className="input-group">
<input
type="text"
id="search_field"
className="form-control"
placeholder="Enter Product Name ..."
onChange={(e) => setKeyword(e.target.value)}
/>
<div className="input-group-append">
<button id="search_btn" className="btn">
<i className="fa fa-search" aria-hidden="true"></i>
</button>
</div>
</div>
</form>
);
};
export default Search;
Home Component
import React, { Fragment, useState } from "react";
import { useParams } from "react-router-dom";
import Pagination from "react-js-pagination";
import MetaData from "./Layouts/MetaData";
import { useDispatch, useSelector } from "react-redux";
import { getAllProducts } from "../Actions/productActions";
import { useEffect } from "react";
import Product from "./Product/Product";
import Loader from "./Layouts/Loader";
import { useAlert } from "react-alert";
const Home = () => {
const [currentPage, setCurrentPage] = useState(1);
const dispatch = useDispatch();
const alert = useAlert();
const { loading, products, error, productsCount, resultPerPage } =
useSelector((state) => state.products);
const { keyword } = useParams();
useEffect(() => {
if (error) {
return alert.error(error);
}
dispatch(getAllProducts(keyword, currentPage));
}, [dispatch, error, alert, keyword, currentPage]);
function setCurrentPageNo(pageNumber) {
setCurrentPage(pageNumber);
}
return (
<Fragment>
{loading ? (
<Loader />
) : (
<Fragment>
<MetaData title="Buy At Discount Price" />
<h1 id="products_heading">Latest Products</h1>
<section id="products" className="container mt-5">
<div className="row">
{products &&
products.map((product) => (
<Product product={product} key={product._id} />
))}
</div>
</section>
{resultPerPage <= productsCount && (
<div className="d-flex justify-content-center mt-5">
<Pagination
activePage={currentPage}
itemsCountPerPage={resultPerPage}
totalItemsCount={productsCount}
onChange={setCurrentPageNo}
nextPageText={"Next"}
prevPageText={"Prev"}
firstPageText={"First"}
lastPageText={"Last"}
itemClass="page-item"
linkClass="page-link"
/>
</div>
)}
</Fragment>
)}
</Fragment>
);
};
export default Home;
Action
import axios from "axios";
import {
ALL_PRODUCTS_REQUEST,
ALL_PRODUCTS_SUCESS,
ALL_PRODUCTS_FAIL,
PRODUCT_DETAILS_REQUEST,
PRODUCT_DETAILS_SUCCESS,
PRODUCT_DETAILS_FAIL,
CLEAR_ERRORS,
} from "../Constants/productConstants";
// Get All Product ( ACTIONS )
export const getAllProducts =
(keyword = "", currentPage = 1) =>
async (dispatch) => {
try {
dispatch({ type: ALL_PRODUCTS_REQUEST });
const { data } = await axios.get(
`/api/v1/products?keyword=${keyword}&page=${currentPage}`
);
dispatch({
type: ALL_PRODUCTS_SUCESS,
payload: data,
});
} catch (error) {
dispatch({
type: ALL_PRODUCTS_FAIL,
payload: error.response.data.message,
});
}
};
// Product Details ( ACTIONS )
export const getProductDetails = (id) => async (dispatch) => {
try {
dispatch({ type: PRODUCT_DETAILS_REQUEST });
const { data } = await axios.get(`/api/v1/product/${id}`);
dispatch({
type: PRODUCT_DETAILS_SUCCESS,
payload: data.product,
});
} catch (error) {
dispatch({
type: PRODUCT_DETAILS_FAIL,
payload: error.response.data.message,
});
}
};
// Clearing eroor message
export const clearErrors = () => async (dispatch) => {
dispatch({ type: CLEAR_ERRORS });
};

You can try to use the useNavigate() hook instead of createBrowserHistory()
First import useNavigate
import { useNavigate } from 'react-router-dom';
then just do this after importing
const navigate = useNavigate();
const searchHandler = (e) => {
e.preventDefault();
if (keyword.trim()) {
navigate(`/search/${keyword}`);
} else {
navigate("/");
}
};

Related

how pass function between sibilngs components in reactjs

so i have 2 component are sibiling one call and
and i went to pass a function from NavBar component to Login component
i try to do that becouse i went when the user login i can call to function from the NavBar to update the state in the Navbar component
i add here the code of 2 components
this the NavBar component and i went to pass the userLog function from her
import axios from "axios";
import React, { useEffect, useState } from "react";
import { NavLink } from "react-router-dom";
import Cookies from 'js-cookie';
import Login from "../auth/login/Login";
import { useLocation } from 'react-router-dom';
import './navBar.css'
function NavBar() {
const [cookie, setCookie] = useState(null)
const userLog = () => {
if (localStorage.getItem("login")) {
setCookie(true)
}
}
const logout = async () => {
console.log("logout")
const res = await axios.get('http://127.0.0.1:3000/users/logout', { withCredentials: true })
.then(res => {
if (res.data.status == "success") {
console.log('sss')
setCookie(false)
localStorage.setItem('login', 'false')
}
})
}
return (
<div className="nav-bar-container">
<img className="imgLogo" src="data:image/png;base64,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" />
<ul className="main-nav">
<li><NavLink className="navLink" to="/">Home</NavLink></li>
<li><NavLink className="navLink" to="/">Contact</NavLink></li>
<li><NavLink className="navLink" to="/login">Login</NavLink></li>
{/* {cookie === true ? <li><NavLink className="navLink" to="/">username</NavLink></li> : <li><NavLink className="navLink" to="/login">Login</NavLink></li>} */}
<li><NavLink onClick={logout} className="navLink" to='/' >Logout</NavLink></li>
<li><NavLink className="navLink" to="/sign-in">Signin</NavLink></li>
{/* <button onClick={() => user()}>user</button> */}
{/* <button onClick={() => log()}>dddd</button> */}
</ul>
</div>
);
}
export default NavBar;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
this the Login component and i went to get the userLog function and call it in the login function that i call by onClick
import axios from "axios";
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import { useLocation } from 'react-router-dom';
import './Login.css'
function Login(props) {
const [email, setEmail] = useState("")
const [password, setPass] = useState("")
const [cookie, setCookie] = useState(Boolean)
let navigate = useNavigate();
const location = useLocation()
const login = async (props) => {
console.log(email, password);
try {
const res = await axios.create({ withCredentials: true }).post(`http://127.0.0.1:3000/users/login`, {
email: email,
password: password
});
if (!res) {
return "not work"
}
console.log(res.data.data.user)
localStorage.setItem('login', 'true')
navigate("/", { replace: true });
} catch (error) {
console.log(error);
}
};
return (
<div className="pop-container">
<div className="popup">
<div className="content">
<h1>Sign in</h1>
<div className="input-field"><input placeholder="Email" className="validate" onChange={(e) => setEmail(e.target.value)} /></div>
<div className="input-field"><input placeholder="Password" className="validate" onChange={(e) => setPass(e.target.value)} /></div>
<button onClick={(e) => login(e)} className="second-button">Sign in</button>
<p>Don't have an account? Sign Up</p>
</div>
</div>
</div>
);
}
export default Login;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I try to use useLocation and also pass state in NavLink in the NavLink component
but thay cant get a function
to pass some date like string i success its not a problem but function I not success
There isn't a direct way to pass between sibling components. One option is to pass from sibling 1 -> parent component -> sibling 2. So with your "NavBar" and "Login" components you can lift state up from Navbar to the App (parent) component and then down to the Login component.
Option 2 would be setting up something like a useContext hook. Context is for setting global state variables to avoid unnecessary prop drilling.

useContext() returns null value

I am trying to use useContext to get the current logged in user details. I am getting an error in my console which says:
Uncaught TypeError: user is null
children Animate.jsx:79
Animate Animate.jsx:76
I am getting this error whenever I Logout. I am facing no errors in the console when I am logged in.
Here is the code:
Context.js File:
import { onAuthStateChanged } from "firebase/auth";
import { useEffect, useState } from "react";
import { createContext } from "react";
import { auth } from "./firebase";
export const Context = createContext()
const ContextProviderfunc=({children})=>{
const use={
"mail":'history'
}
const [user,setuser]=useState({});
useEffect(()=>{
const unsubscribe = onAuthStateChanged(auth,(currentUser)=>{
// console.log(currentUser);
setuser(currentUser);
})
return ()=>{
unsubscribe();
}
},[])
return(
<Context.Provider value={user}>
{children}
</Context.Provider>
)
}
export default ContextProviderfunc
Animate.jsx File:
import React from 'react'
import {
BrowserRouter as Router, Routes, Route, useLocation, Link
} from 'react-router-dom'
import Navbar from './Navbar'
import RecipeCard from './RecipeCard'
import Details from './Details'
import { AnimatePresence, motion } from "framer-motion"
import Add from './Add'
import clicked from './RecipeCard'
import { useState } from 'react'
import Login from './Login'
import Register from './Register'
import Protected from './Protected'
import Logout from './Logout'
import Myrecipe from './Myrecipe'
import { useContext } from 'react'
import { Context } from '../Context'
export default function Animate(props) {
const user=useContext(Context)
const [pname, setpname] = useState()
function assign(nigga) {
setpname(nigga);
console.log(nigga);
}
const location = useLocation()
return (
<motion.div className='all'
>
<AnimatePresence>
<Routes location={location} key={location.pathname}>
<Route path='/Login' element={<Login />} />
<Route path='/Register' element={<Register />} />
<Route path='*' element={[<Protected><Navbar /></Protected>, <h2>Recipes</h2>,
<div className='recipes'>
{props.query ? props.query.map((object, i) => (
<Link className='lin' to='/Details'>
<div onClick={() => assign(object.Name)}>
<Protected><RecipeCard
src={object.src}
name={object.Name}
ingredients={object.Ingredients}
steps={object.Steps}
key={i}
/></Protected>
</div></Link>
)) : "Loading"}
<Link className='lin' to='/Add'>
<div className='cardcont'>
<img src='https://cdn.pixabay.com/photo/2017/11/10/05/24/add-2935429_960_720.png' alt="1" className='cardimg' />
<div className='cardbody'>
<h3>Add</h3>
</div>
</div></Link>
</div>
]} />
<Route path='/MyRecipe' element={[<Protected><Navbar /></Protected>, <h2>My Recipes</h2>,
<Protected>
<div className='recipes'>
{props.query2 ? props.query2.map((object, i) => {
if(user.email==object.email){
console.log(user.email);
return(<Link className='lin' to='/Details'>
<div onClick={() => assign(object.Name)}>
<Protected><RecipeCard
src={object.src}
name={object.Name}
ingredients={object.Ingredients}
steps={object.Steps}
key={i}
/></Protected>
</div></Link>)
}
}
) : "Loading"}
<Link className='lin' to='/Add'>
<div className='cardcont'>
<img src='https://cdn.pixabay.com/photo/2017/11/10/05/24/add-2935429_960_720.png' alt="1" className='cardimg' />
<div className='cardbody'>
<h3>Add</h3>
</div>
</div></Link>
</div>
</Protected>
]} />
<Route path='/Details' element={
[<Navbar />, props.query ? props.query.map((object, m) => {
if (pname == object.Name) {
console.log(object.Name);
return (<Details
src={object.src}
name={object.Name}
Ingredients={object.Ingredients}
Steps={object.Steps}
key={m}
/>)
}
}) : "Loading"]} />
<Route path='/Add' element={[<Navbar />, <Add />]} />
</Routes>
</AnimatePresence>
</motion.div>
)
}
line 79 of Animate.jsx
if(user.email==object.email){
console.log(user.email);
App.js file:
import Navbar from './components/Navbar';
import RecipeCard from './components/RecipeCard';
import { useContext, useEffect, useState } from 'react';
import { auth, db, storage } from './firebase'
import { collection, addDoc, getDocs, doc } from "firebase/firestore";
import { async } from '#firebase/util';
import Details from './components/Details'
import Animate from './components/Animate';
import {BrowserRouter as Router, Route,Routes} from 'react-router-dom'
import Add from './components/Add';
import ContextProviderfunc from './Context';
import { Context } from './Context';
function App() {
const [query, setquery] = useState()
const [query2, setquery2] = useState()
const [recipe, setrecipe] = useState()
const add = async (e) => {
e.preventDefault()
try {
const docRef= await addDoc(collection(db, "recipe"),
{
src: 'https://images.immediate.co.uk/production/volatile/sites/30/2017/02/Two-panna-cotta-on-plates-298e616.jpg',
ingredients: ['Dish'],
steps: ['Description']
}, {
src: 'https://imagesvc.meredithcorp.io/v3/mm/image?url=https%3A%2F%2Fstatic.onecms.io%2Fwp-content%2Fuploads%2Fsites%2F43%2F2022%2F04%2F19%2F22749-the-best-banana-pudding-mfs-366-1x1-1.jpg',
ingredients: ['Dish'],
steps: ['Description']
});
// console.log('morein');
// console.log("Document written with ID: ", docRef.id);
} catch (error) {
console.log('morein');
console.error("Error adding document: ", error);
}
}
useEffect(() => {
const getrecipe = async () => {
const data = await getDocs(collection(db, 'recipe'))
const data2 = await getDocs(collection(db, 'userrecipe'))
console.log(data);
setquery(data.docs.map((doc) => (
{
...doc.data(), id: doc.id
})
))
setquery2(data2.docs.map((doc) => (
{
...doc.data(), id: doc.id
})
))
console.log(query);
};
getrecipe();
}, []);
useEffect(() => {
// searchRecipes();
}, [])
return (
<div>
<ContextProviderfunc>
<Router>
<Animate query={query} query2={query2}/>
</Router>
</ContextProviderfunc>
</div>
);
}
export default App;
These two files I think are needed to debug. If any more code is needed I will provide it. Please find out the issue in the above code
Whenever the user logs out, value of currentUser will become null in here:
onAuthStateChanged(auth,(currentUser)=>{
// console.log(currentUser);
setuser(currentUser); // currentUser is null
})
Since you are updating the state (setuser), The Context Provider rerenders and passes down null as value.
return(
<Context.Provider value={user}> // user is null, and is being passed down
{children}
</Context.Provider>
)
Within Animate you receive the null value.
const user=useContext(Context) // user is null, after loging out.
Long story short, user is at times null within Animate, so you don't have the guarantee to use properties like email, like this line below:
if(user.email==object.email){
console.log(user.email);
The solution: Wherever you need to use user, first check if it equals to null.
If you set logged out user ti be null, you should not expect to retrieve email address of null.
You should check (read from context) if user still logged in.
For example :
if(user) {
return <div>I am logged in user and my email is {user.email} </div>
}
return <div>You are not logged In </div>
Specific to your case: check first user and then user.email to avoid Uncaught TypeError: user is null
if(user && user.email === object.email) .....
This is just a friendly suggestion, which is not related with your question: Use ===instead of == for for information you can read this page

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>

How to render all component after an async call?

I'm new to React and I'm currently setup my first project using Gatsby. Essentially I'm creating a website that use an API created with Strapi. So far, I would like to load the navbar items using an API call like that: http://localhost:3001/sections, where for sections, I mean the items of the navbar.
For doing so, I have defined an Index page like that:
import React from "react"
import Layout from "../components/layout/layout"
import SEO from "../components/layout/seo"
import BGTState from "../context/bgt/bgtState"
import "../styles/css/begreentannery.css"
const IndexPage = () => {
return (
<BGTState>
<Layout>
<SEO title="Home" />
</Layout>
</BGTState>
)
}
export default IndexPage
the BGTState contains the getSections() method that is used inside Layout:
import React, { useContext, useEffect } from "react"
import PropTypes from "prop-types"
import { injectIntl } from "gatsby-plugin-intl"
import BGTContext from "../../context/bgt/bgtContext"
import { Spinner } from "react-bootstrap"
import Footer from "./footer"
import SearchState from "../../context/search/SearchState"
import Search from "../../components/search"
import NavbarMobile from "../../components/layout/navbarMobile"
import NavbarDesktop from "../../components/layout/navbarDesktop"
const Layout = ({ children, intl }) => {
const bgtContext = useContext(BGTContext)
const { loading, getSections, sections } = bgtContext
useEffect(() => {
getSections()
//eslint-disable-next-line
}, [])
return !loading ? (
<>
<NavbarMobile sections={sections} />
<NavbarDesktop sections={sections} />
<SearchState>
<Search />
<div className="container-fluid">
<div className="main">
{children}
<Footer />
</div>
</div>
</SearchState>
</>
) : (
<div className="container" style={{ height: "100vh" }}>
<div className="row h-100 justify-content-center align-items-center">
<Spinner animation="grow" />
</div>
</div>
)
}
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default injectIntl(Layout)
the problem is in the code above, essentially I call useEffect hook which grab the sections from the API. So, until the sections are downloaded, I stop the code like so:
return !loading ? (
this is the getSections() method inside BGTState:
const getSections = async () => {
try {
setLoading()
const res = await axios.get(
`${process.env.API_URL}/sections?_sort=order:ASC`
)
dispatch({
type: GET_SECTIONS,
payload: res.data,
})
} catch (err) {
dispatch({
type: GET_SECTIONS,
payload: err.response.msg,
})
}
}
in the Index page all works fine, but the problem is in the CollectionsPage, infact I have this structure:
import React from "react"
import { injectIntl } from "gatsby-plugin-intl"
import Layout from "../components/layout/layout"
import SEO from "../components/layout/seo"
import BGTState from "../context/bgt/bgtState"
import CollectionState from "../context/collection/collectionState"
import Collection from "../components/collection"
const CollectionsPage = ({ intl }) => {
return (
<BGTState>
<Layout>
<SEO
lang={intl.locale}
title={`${intl.formatMessage({ id: "collections" })}`}
/>
<CollectionState>
<Collection id={1} />
</CollectionState>
</Layout>
</BGTState>
)
}
export default injectIntl(CollectionsPage)
essentially, the component <CollectionState> isn't mounting 'cause in Layout there is the async call on getSections().
So in Collection component, I have:
import React, { useContext, useEffect } from "react"
import CollectionContext from "../context/collection/collectionContext"
import { Link } from "gatsby"
const Collection = ({ id }) => {
const collectionContext = useContext(CollectionContext)
const { loading, collection, getCollection } = collectionContext
useEffect(() => {
getCollection(id)
}, [])
if (loading) return React.Fragment
return (
<div className="container">
<div className="row">
{/*
<img
src={`${process.env.API_URL}${collection.feature_media.url}`}
className="w-100 mt-2 mb-2"
alt={""}
/>*/}
<Link to="#" className="bg-caption bg-no-underline">
fall/winter 20/21
</Link>
</div>
</div>
)
}
export default Collection
which generate that error:
and of course getCollection is not called and will generate other errors in the Collection component
How can I revisit this mechanism? Essentially I have to:
Load all the sections
Load all the components

Categories

Resources