Not rendering with react-router-dom - javascript

Before I used react-router-dom and I hadn't any problem and I changed my route without any problem.
But now I bring hook inside of my project and I got a problem.
When I use <NavLink>, my route changes but it does not render anything from my component. When I refresh my page, the component will appear.
My App.js:
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
const routes={
route: `/main/symbol/:title/:id`,
exact: true,
component: Symbol,
},
{
route: `/main/symbolDetails/:title/:id`,
exact: true,
component: SymbolDetails,
},
render(){
<Router>
<Switch>
{routes.map((route, k) => (
<Route
key={k}
exact={route.exact}
path={route.route}
component={route.component}
/>
))}
</Switch>
</Router>
}
My Home.js:
(in this component I use navlink for changing my page)
import GridContainer from "../../../components/Grid/GridContainer.js";
import "perfect-scrollbar/css/perfect-scrollbar.css";
// #material-ui/core components
import { makeStyles } from "#material-ui/core/styles";
// core components
import Navbar from "../../../components/Navbars/Navbar.js";
import Sidebar from "../../../components/Sidebar/Sidebar.js";
const useStyles = makeStyles(styles);
export default function Admin({ ...rest }) {
// styles
const classes = useStyles();
const [data, setData] = useState([]);
useEffect(() => getSymbolGroup(), []);
const getSymbolGroup = async () => {
let { data } = await symbolGroup.getSymbolGroup();
setData(data.data);
// console.log("data", data);
};
return (
<div className={classes.wrapper}>
<Sidebar
logoText={"Creative Tim"}
logo={logo}
color={color}
{...rest}
/>
<div className={classes.mainPanel}>
<Navbar
/>
<div className={classes.content}>
<div className={classes.container}>
<GridContainer>
{data &&
data.length &&
data.map((x, key) => {
return (
<div className="Subscrip Bshadow ">
<NavLink
to={`/main/symbol/${x.title}/${x.id}`}
className="a rightanime display awidth flexd"
exact
>
<div className="">
<div className="iconpro display">
<img
className="imgwidth "
src={`http://api.atahlil.com/Core/Download/${x.fileId}`}
/>
</div>
</div>
<div className="">
<p style={{ color: "#a3b0c3", width: "100%" }}>
{x.title}
</p>
</div>
</NavLink>
</div>
);
})}
</GridContainer>
</div>
</div>
)}

I realized my problem.
as I say it was correct when I use in class component.
it is not correct because of my useEffect (hook).
I had to use accolade (I mean {}) after use UseEffect in Home.js component.
home.js
useEffect(() => getSymbolGroup(), []); //it is not correct and I need to refresh my page to render
and the way I had to use useEffect is:
useEffect(() => {
getSymbolGroup();
}, []);
// its correct and does not need to refresh page

Related

BrowserRouter not loading pages [duplicate]

This question already has an answer here:
Why I receive blank page? React
(1 answer)
Closed 11 months ago.
I've used BrowserRouter here, and wrapped the within a tag.
But the problem is, the ShowTodoList page is not rendering.
Is this syntactically correct?
App.js file
import {BrowserRouter, Route, Routes} from 'react-router-dom';
import React, { lazy } from 'react';
import "./App.scss";
const ShowTodoList = lazy(() => import("./components/showTodoList"));
const CreateTodo = lazy(() => import("./components/createTodo"));
function App() {
return (
<div className="app-contents">
TODO - LIST
<BrowserRouter>
<Routes>
<Route path="/" component={ShowTodoList} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
ShowTodoList.jsx
import { useState, useEffect } from "react";
import axios from "axios";
import { Link } from "react-router-dom";
import { UpdateTodo } from "./updateTodo";
function TodoCard({ data, handleEdit, handleDelete }) {
const { _id, title, description } = data;
return (
<li key={_id}>
<div className="title-description">
<h3>{title}</h3>
<p>{description}</p>
</div>
<div className="button-container">
<button className="button" name={_id} onClick={handleEdit}>
edit
</button>
<button className="button" name={_id} onClick={handleDelete}>
delete
</button>
</div>
</li>
);
}
export function ShowTodoList() {
const [todo, setTodo] = useState([]);
const [open, setOpen] = useState(false);
const [id, setId] = useState("");
const [update, setUpdate] = useState(false);
useEffect(
function () {
axios
.get("http://localhost:8000/api/todo")
.then((res) => {
console.log(res.data);
setTodo(res.data);
})
.catch((err) => {
console.log(err.message);
});
},
[update]
);
function handleEdit(e) {
setId(e.target.name);
setOpen(true);
}
function handleUpdate() {
console.log("update:", update, !update);
setUpdate(!update);
}
function handleDelete(e) {
axios.delete(`http://localhost:8000/api/todo/${e.target.name}`);
setTodo((data) => {
return data.filter((todo) => todo._id !== e.target.name);
});
}
function handleClose() {
setId("");
setOpen(false);
}
return (
<section className="container">
<Link to="/create-todo" className="button-new">
<button className="button">New</button>
</Link>
<section className="contents">
<h1>TODO</h1>
<ul className="list-container">
{todo.map((data) => (
<TodoCard
data={data}
handleEdit={handleEdit}
handleDelete={handleDelete}
/>
))}
</ul>
</section>
{open ? (
<section className="update-container">
<div className="update-contents">
<p onClick={handleClose} className="close">
×
</p>
<UpdateTodo
_id={id}
handleClose={handleClose}
handleUpdate={handleUpdate}
/>
</div>
</section>
) : (
""
)}
</section>
);
}
I'm getting a blank page as below:enter image description here
Could anybody please check the codes and point out where I'm going wrong?
If you are using react-router version 6, we don't have component props in this version, and you should use element instead of it.
import { BrowserRouter, Route, Routes } from "react-router-dom";
import React, { lazy, Suspense } from "react";
const ShowTodoList = lazy(() => import("./components/showTodoList"));
const CreateTodo = lazy(() => import("./components/createTodo"));
function App() {
return (
<div className="app-contents">
TODO - LIST
<Suspense fallback={<div>Loading...</div>}>
<BrowserRouter>
<Routes>
<Route path="/" element={<ShowTodoList />} />
</Routes>
</BrowserRouter>
</Suspense>
</div>
);
}
export default App;

React pass fetched data from API to another component

I am fetching few products from an API, and displaying them in card. There is a More Details link on the cards, where if the user clicks on it, it will take the user to the selected product details page. My routing to productDetails page works, But I am having troubles to find a way to pass the fetched data to the productDetails page as props.
This is what I have so far:
My FeaturedProduct.js:
import React from "react";
import { useState, useEffect } from "react";
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import ProductDetails from "./ProductDetails";
import axios from "axios";
function FeaturedProduct(props) {
const [products, setProducts] = useState([]);
useEffect(() => {
fetchProducts();
}, []);
function fetchProducts() {
axios
.get("https://shoppingapiacme.herokuapp.com/shopping")
.then((res) => {
console.log(res);
setProducts(res.data);
})
.catch((err) => {
console.log(err);
});
}
return (
<div>
<h1> Your Products List is shown below:</h1>
<div className="item-container">
{products.map((product) => (
<div className="card" key={product.id}>
{" "}
<h3>{product.item}</h3>
<p>
{product.city}, {product.state}
</p>
<Router>
<Link to="/productdetails">More Details</Link>
<Switch>
<Route path="/productdetails" component={ProductDetails} />
</Switch>
</Router>
</div>
))}
</div>
</div>
);
}
export default FeaturedProduct;
My Product Details Page:
import React from "react";
import FeaturedProduct from "./FeaturedProduct";
function ProductDetails(props) {
return (
<div>
<div>
<h1>{props.name}</h1>
<h1>{props.color}</h1>
</div>
</div>
);
}
export default ProductDetails;
I am still learning but this is what I would do:
<Route path="/productdetails">
<ProductDetails product={product}/>
</Route>
====
On ProductDetails you can destructure the props:
function ProductDetails(props) {
const {name, color} = props.product;
return (
<div>
<div>
<h1>{name}</h1>
<h1>{color}</h1>
</div>
</div>
);
}
export default ProductDetails;
Pass it as an element with props, if you are using v 6; sorry I didn't ask which version. >
<Switch>
<Route path="/productdetails" element={<ProductDetails {...props} />}/>
</Switch>
if version v4/5 use the render method >
<Route path="/productdetails" render={(props) => (
{ <ProductDetails {...props} />} )}/>
//pass it this way
<Switch>
<Route
path="/productdetails"
render={() => (
{ <ProductDetails product={product}/>})}/>
/>
</Switch>

How to transition from one page to another in react app

i am trying create a transition screen from one page to the other
function MainPage(){
return (
<div>
{pagestate.navigating == "true" ? (
<FadeIn>
<div className="d-flex justify-content-center align-items-center">
<h1>signing you in ....</h1>
<Link to="/" color="black" >sign in</Link>
{pagestate.loading =="false" ? (
<Lottie options={defaultOptions} height={120} width={120} />
) : (
<Lottie options={defaultOptions2} height={220} width={120} />
)}
</div>
</FadeIn>
) : (
<div>
<h1>hello world</h1>
<Link to="/" color="black" >sign in</Link>
</div>
)}
The code works fine but I want it to navigate to /page2 when pagestate.loading = "false". I was able to achieve the page navigation with using
const history = useHistory()
then call navigation like
history.push('/page2')
I tried couple of method but could not get it work inside the transition logic.
How can I incorporate to the navigation into a new page after loading state has been changed to false in the transition logic above?
Encountered that a couple of days ago, i found a solution to it but it’s kinda weird,i’ve done it using redux, i’ve made a Link Component Called LinkWithAnimation,created a reducer as RouteReducer which will store current transition state, 2 states:
First one is For Transitioning In.
Second one is For Transitioning Out.
Wrapped my application with a div and passed the Transition that’s stored in redux, everytime LinkWithAnimation Is clicked This Is What Happens:
Dispatch An Action For Transitioning In
Wait(Delay) Till the Transition Has Finished(Depending On The Duration Of It)
Dispatch An Action for Transitioning Out.
And then push the new path using History API.
Note: Make Use Of Redux Thunk.
ActionTypes.js
export const ActionsType = {
...otherActions,
ANIMATION_IN: "animation-in",
ANIMATION_OUT: "animation-out",
};
ActionsCreator.js
import { ActionsType } from "./ActionsType.js";
import { history } from "../index.js";
export const ActionsCreator = {
...otherActionCreators,
userLogout: () => ({ type: ActionsType.LOGOUT }),
animateIn: () => ({ type: ActionsType.ANIMATION_IN }),
animateOut: () => ({ type: ActionsType.ANIMATION_OUT }),
pageTransition: (duration, path) => {
return async (dispatch) => {
const delay = async () => {
return new Promise((resolve) => setTimeout(resolve, duration));
};
dispatch(ActionsCreator.animateOut());
await delay();
dispatch(ActionsCreator.animateIn());
history.push(path);
};
},
};
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Router } from "react-router-dom";
import { createBrowserHistory } from "history";
export const history = createBrowserHistory();
ReactDOM.render(
<Router history={history}>
<React.StrictMode>
<App />
</React.StrictMode>
</Router>,
document.getElementById("root")
);
LinkWithAnimation.js
import React, { useRef, useEffect } from "react";
import { Link } from "react-router-dom";
import { ActionsCreator } from "../actions/ActionsCreator.js";
import { connect } from "react-redux";
const LinkWithAnimation = ({
className,
additionalFunction,
PageTransitioning,
to,
children,
style,
component,
ReactTo,
disabled,
}) => {
const LinkRef = useRef();
// This Effect To Handle Page Transition Once The User Is Signed In
useEffect(() => {
if (ReactTo === true) {
LinkRef.current.click();
}
}, [ReactTo]);
const componentProp =
component !== undefined
? {
component: component,
}
: {};
return (
<>
<Link
onClick={async () => {
if (disabled) return;
PageTransitioning(230, to);
if (additionalFunction !== undefined) {
additionalFunction();
}
}}
ref={LinkRef}
className={className}
style={{ ...style }}
{...componentProp}
>
{children}
</Link>
</>
);
};
const mapDispatchToProps = (dispatch) => ({
PageTransitioning: (duration, path) => {
dispatch(ActionsCreator.pageTransition(duration, path));
},
});
export default connect(null, mapDispatchToProps)(LinkWithAnimation);
Main.js
import React, { Fragment } from "react";
import { Switch, Route } from "react-router-dom";
import { connect } from "react-redux";
import Homepage from "./Homepage/Homepage.js";
import Signup from "./Signup/Signup.js";
import UserInterface from "./UserInterface/UserInterface.js";
import { SignIn } from "./SignIn/SignIn.js";
import { useRouteTransitionScroll } from "../hooks/useRouteTransitionScroll.js";
const Main = ({ keyframe }) => {
useRouteTransitionScroll({
from: "/signup",
to: "/home",
scroll_y: 650,
});
return (
<Switch component={Fragment}>
<div
style={{
animationName: keyframe,
animationDuration: "250ms",
animationTimingFunction: "linear",
}}
>
<Route path="/mainpage">
<UserInterface />
</Route>
<Route path="/home">
<Homepage />
</Route>
<Route path="/signin">
<SignIn />
</Route>
<Route path="/signup">
<Signup />
</Route>
</div>
</Switch>
);
};
const mapStateToProps = (state) => ({
keyframe: state.Route.animationName,
});
export default connect(mapStateToProps)(Main);

Passing refs from Component to Component in React

So I am not sure if passing refs would be the best thing to do but it's kinda what I have set-out to do tell me if there is a better option..
So I am trying to have an onClick of a nav link, scroll down to the the div "contactForm".
App.js
import ContactForm from './components/ContactForm'
import ParllaxPage from './components/ParllaxPage'
import NavigationBar from './components/NavigationBar'
import React from 'react';
import './App.css';
const App = () => {
return (
< div cssClass="App" >
<body>
<span><NavigationBar /></span>
<ParllaxPage cssClass="parallax-wrapper" />
<ParllaxPage cssClass="parallax-wrapper parallax-pageOne" />
<ContactForm />
</body >
</div >
);
}
export default App;
I was trying to use forwardRef but I am not sure that I was doing it correctly so...
NavigationBar.js
import ContactForm from "./ContactForm";
import React, { useRef } from "react";
import App from "../App";
import { Nav, Navbar, Form, FormControl, Button } from "react-bootstrap";
const ContactFormRef = React.forwardRef((props, ref) => (
<ContactForm className="contactForm" ref={ref}>
{props.children}
</ContactForm>
));
const scrollToRef = (ref) => ref.current.scrollIntoView({ behavior: "smooth" });
const NavigationBar = () => {
const ref = React.forwardRef(ContactFormRef);
return (
<Navbar bg="light" expand="lg">
<Navbar.Brand href="#home">A1 Gutters</Navbar.Brand>
<Navbar.Toggle aria-controls="b casic-navbar-nav" />
<Nav className="mr-auto">
<Nav.Link href="#home">Home</Nav.Link>
<Nav.Link href="#link">Link</Nav.Link>
<Nav.Link href="#" onClick={console.log(ref)}>
Contact
</Nav.Link>
</Nav>
</Navbar>
);
};
export default NavigationBar;
I don't think the other files really need to be shown, I am just trying to get the className out of the ContactForm component so I can scroll to it onClick.. I currently just have a console.log in the onClick.
Using Hooks will simplify here.
Have state variable for gotoContact and ref for contactRef
Add click handler for navigation link contact
Add useEffect hook and when ever use click on contact and ref is available (value in ref.current) then call the scroll to view)
import ContactForm from "./components/ContactForm";
import ParllaxPage from "./components/ParllaxPage";
import React, { useState, useEffect, useRef } from "react";
import "./App.css";
const NavigationBar = ({ onClickContact }) => {
return (
<Navbar bg="light" expand="lg">
<Navbar.Brand href="#home">A1 Gutters</Navbar.Brand>
<Navbar.Toggle aria-controls="b casic-navbar-nav" />
<Nav className="mr-auto">
<Nav.Link href="#home">Home</Nav.Link>
<Nav.Link href="#link">Link</Nav.Link>
<Nav.Link href="#" onClick={() => onClickContact()}>
Contact
</Nav.Link>
</Nav>
</Navbar>
);
};
const App = () => {
const [gotoContact, setGotoContact] = useState(false);
const contactRef = useRef(null);
useEffect(() => {
if (gotoContact && contactRef.current) {
contactRef.current.scrollIntoView();
setGotoContact(false);
}
}, [gotoContact, contactRef.current]);
return (
<div cssClass="App">
<body>
<span>
<NavigationBar onClickContact={() => setGotoContact(true)} />
</span>
<ParllaxPage cssClass="parallax-wrapper" />
<ParllaxPage cssClass="parallax-wrapper parallax-pageOne" />
<div ref={contactRef}>
<ContactForm />
</div>
</body>
</div>
);
};
export default App;
You should identify the div "contactForm" with an id and have an anchor tag point to it:
<div id="contactForm"></div>
You can add scroll-behaviour: smooth to the body in CSS
No need to create a separate ContactFormRef wrapper. Simply use React.forwardRef in ContactForm itself. Those not passing a ref will not have to know it forwards refs.
Then, remember to further pass the ref received to a native element or use useImperativeHandle hook to add methods to it without passing it further down.
const ref = React.forwardRef(ContactFormRef)
This is wrong.
You should do it the same as with native components:
const ref = useRef()
return <ContactForm ref={ref} >
// etc
</ContactForm>
You are not rendering the ContactFormRef, so the reference points no nothing!
App.js should be like:
...
const App = () => {
const myNestedRefRef=React.useRef();
return (
...
<NavigationBar contactRef={myNestedRefRef}/>
...
<ContactForm ref={myNestedRefRef} />
...
);
}
...
ContactForm.js
...
function ContactForm=React.forwardRef((props, ref) => (
<form ref={ref}>
...
</form>
));
NavigationBar.js
const NavigationBar = ({contactRef}) => {
return (
...
<Nav.Link href="#" onClick={console.log(contactRef)}>
...
);
};
Consider that
If the <ContactForm/> hasn't been rendered yet, the ref will look like {current:null}

React hook Redirect on component mount

I am trying to manage session after successful login while redirecting to some page on form submit.
I would do this usually, in a class component:
componentDidMount() {
if (context.token) {
return <Redirect to="/" />
}
}
But I want to use React hooks, therefore; the following code is not redirecting anywhere:
import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Switch, Route, Redirect, Link } from "react-router-dom";
es6
const HomePage = props => (
<div>
<h1>Home</h1>
</div>
);
const AboutUsPage = props => {
useEffect(() => {
redirectTo();
}, []);
return (
<div>
<h1>About us</h1>
</div>
);
};
function redirectTo() {
return <Redirect to="/" />;
}
function App() {
return (
<div className="App">
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/us">About us</Link>
</nav>
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/us" component={AboutUsPage} />
</Switch>
</BrowserRouter>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Working sandbox: https://codesandbox.io/s/blue-river-6dvyv?fontsize=14
I have read that if the hook useEffect() returns a function it will only work when the component unmounts. But it should redirect when the component is being mounted.
Any suggestions? Thanks in advance.
You could set redirect variable on the state and based on it redirect in render:
const AboutUsPage = props => {
const [redirect, setRedirect] = useState(false);
useEffect(() => {
setRedirect(true); // Probably need to set redirect based on some condition
}, []);
if (redirect) return redirectTo();
return (
<div>
<h1>About us</h1>
</div>
);
};
You could have it so that the component selectively renders the page based on whether or not the page is given a token.
const AboutUsPage = ({token}) => (
token ? (
<Redirect to="/" />
) : (
<div>
<h1>About us</h1>
</div>
)
);
However, if you would still like to use context when implementing this with React Hooks you can read up on how to use context with hooks in this article. It shows you how you can incorporate context into React with only a few lines of code.
import React, {createContext, useContext, useReducer} from 'react';
export const StateContext = createContext();
export const StateProvider = ({reducer, initialState, children}) =>(
<StateContext.Provider value={useReducer(reducer, initialState)}>
{children}
</StateContext.Provider>
);
export const useStateValue = () => useContext(StateContext);
Done with hooks and context, your AboutUsPage component would resemble something like this.
import { useStateValue } from './state';
const AboutUsPage = () => {
const [{token}, dispatch] = useStateValue();
return token ? (
<Redirect to="/" />
) : (
<div>
<h1>About us</h1>
</div>
);
};
import {Redirect, Switch} from "react-router-dom";
and inside Switch....
<Switch>
<Redirect exact from="/" to="/home" />
</Switch>
This solved my issue.

Categories