Rendering of the timer stops while routing from one component to another - javascript

So I have made a simple countdown timer which stops rendering the updated time if I route to another component. I have used a setInerval() which updates the countdown time every second, and whenever I route to another component the setInterval() keeps running but no rendering happens and the countdown timer sets back to its starting time.
App
import { Route, Routes } from "react-router-dom";
import Countdown from "./components/Countdown";
import Timer from "./components/Timer";
const App = () => {
return (
<>
<Routes>
<Route path="/" element={<Countdown />} />
<Route path="timer" element={<Timer />} />
</Routes>
</>
);
};
export default App;
Countdown
import { useState } from "react";
import { Link } from "react-router-dom";
const Countdown = () => {
const [time, setTime] = useState(600);
const startTimer = () => {
const start = Date.now();
const updateTime = () => {
const updatedTime = time - (((Date.now() - start) / 1000) | 0);
setTime(updatedTime);
console.log("Set Interval running");
};
setInterval(updateTime, 1000);
};
const minutes = (time / 60) | 0;
const seconds = time % 60 | 0;
return (
<>
<h3>
{minutes}:{seconds}
</h3>
<p>Start the timer first 👇</p>
<button onClick={startTimer}>START</button>
<p>After starting the timer go this component 👇</p>
<Link to="timer">
<button>Go to Timer</button>
</Link>
</>
);
};
export default Countdown;
Timer
import { Link } from "react-router-dom";
const Timer = () => {
return (
<>
<p>
Now go back to the Countdown component, the timer is reset and the
setInterval() is still running. How can I avoid this issue ?
</p>
<Link to="/">
<button>Go back to Countdown</button>
</Link>
</>
);
};
export default Timer;
Here's the link to the application - codesandbox.io
With my little beginner knowledge I tried to store the updated time in localStorage every second and then whenever the component rerenders back I tried to fetch it from localStorage and start the timer but it didn't work as anything inside the setInterval() did't work when routed to another component.

The state value of time is relevant only for the active component. If you hop onto a different component and then come back, the state value resets.
To avoid this you can set up context API which helps in data sharing between components.
Check out this article to learn more.

Issue
The issue you see here is caused by the state being located in the Countdown component. When you navigate from the "/" route to the "/timer" route Countdown is unmounted. The reason the interval is still running is because there is no cleanup function to clear the interval when Countdown unmounts.
Solution
The solution is to Lift State Up to a common ancestor and pass the time state and startTimer callback down as props to children/descendent components that care for them.
Since you are using react-router-dom a trivial solution would be to render a layout route component that holds the state and setter and provides them via a React Context.
Example:
TimerLayout
import { useEffect, useRef, useState } from "react";
import { Outlet } from "react-router-dom";
const TimerLayout = () => {
const [time, setTime] = useState(600);
const timerRef = useRef();
useEffect(() => {
return () => {
clearInterval(timerRef.current);
};
}, []);
const startTimer = () => {
console.log("Set Interval running");
setTime(600);
const tick = () => {
setTime((time) => time - 1);
};
timerRef.current = setInterval(tick, 1000);
};
return <Outlet context={{ startTimer, time }} />;
};
export default TimerLayout;
App
import { Route, Routes } from "react-router-dom";
import TimerLayout from "./components/TimerLayout";
import Countdown from "./components/Countdown";
import Timer from "./components/Timer";
const App = () => {
return (
<Routes>
<Route element={<TimerLayout />}>
<Route path="/" element={<Countdown />} />
<Route path="timer" element={<Timer />} />
</Route>
</Routes>
);
};
export default App;
Consumers would access the provided Context value using the useOutletContext hook. Here the minutes and seconds remaining can be derived from the passed time state.
CountDown
import { Link, useOutletContext } from "react-router-dom";
const Countdown = () => {
const { time, startTimer } = useOutletContext();
const minutes = String(Math.floor(time / 60)).padStart(2, "0");
const seconds = String(time % 60).padStart(2, "0");
return (
<>
<h3>
{minutes}:{seconds}
</h3>
<p>Start the timer first 👇</p>
<button onClick={startTimer}>START</button>
<p>After starting the timer go this component 👇</p>
<Link to="timer">
<button type="button">Go to Timer</button>
</Link>
</>
);
};
export default Countdown;

Related

React, passing state from a Child component to the Parent

I'm just learning React and ran into a problem. I'm making a bunch of counter components that look like this :
The problem is that I have defined the state in each of these counters which is 3 of them and I'd like to pass the value (number) into the parent so I can add it up and display the total count.
Here is my child counter component:
import React, { useState } from "react";
const Counter = () => {
const [count, setcount] = useState(0)
const handleIncrement=()=>{
setcount(count+1);
}
const handleDecrement=()=>{
setcount(count+-1);
}
return (
<div>
<button onClick={()=>{handleIncrement()}}>+</button>
<span>{count}</span>
<button onClick={()=>{handleDecrement()}}>-</button>
</div>
);
};
export default Counter;
And here is the parent which I want to pass my values to so I can add them up and show the total :
import React from 'react'
import Counter from './Counter'
const Counters = () => {
return (
<>
<h3>totalcount:</h3>
<Counter/>
<Counter/>
<Counter/>
</>
)
}
export default Counters
What I tried was to make multiple states but I can't get a good way to make this. I know there's an easy answer for this and I'm making it too complicated. If you guys have other optimization for my code please share.
In React state goes top to bottom. A nested component can update the state of a parent if a function defined in the parent has been passed to it as props. Which means, what you wanna do is not possible as your code is set up. A way to achieve what you are looking for is:
Pass setCounter down to each Counter instance as props, like so:
import React, { useState } from 'react'
import Counter from './Counter'
const Counters = () => {
const [countOne, setCountOne] = useState(0)
const [countTwo, setCountTwo] = useState(0)
const [countThree, setCountThree] = useState(0)
return (
<>
<h3>totalcount: {countOne + countTwo countThree} </h3>
<Counter count = {countOne} setCount = {setCountOne} />
<Counter count = {countTwo} setCount = {setCount} />
<Counter count = {countThree} setCount = {setCountThree} />
</>
)
}
export default Counters
Get setCounter from the props inside Counter and use it where you want:
import React, { useState } from "react";
const Counter = ({count, setCount}) => {
const handleIncrement=()=>{
setCount(count+1);
}
const handleDecrement=()=>{
setCount(count+-1);
}
return (
<div>
<button onClick={()=>{handleIncrement()}}>+</button>
<span>{count}</span>
<button onClick={()=>{handleDecrement()}}>-</button>
</div>
);
};
export default Counter;

ScrollToTop implementation with v6 of react router dom [duplicate]

How to scroll to top on route change with react router dom v6?
I have tried this, react-router scroll to top on every transition, which was my solution to make my page scroll to top on route change when I use react-router-dom v5. Now, I am using react-router-dom v6 and this solution does not work.
I tried React-router v6 window.scrollTo does not work and does not work for me.
I tried https://github.com/remix-run/react-router/issues/7365, which is to use the preload prop to trigger the scrollTo(0,0), also does not work for me.
Well I'm not really sure what your layout looks like but inside your <BrowserRouter /> you can wrap your app in a wrapper and check for the location change in a useLayoutEffect. Then if there is a change you can scroll to the top. Here is a crude example.
Codesandbox
import { BrowserRouter, Routes, Route, Link, useLocation } from 'react-router-dom'
import { useLayoutEffect } from 'react'
const Wrapper = ({children}) => {
const location = useLocation();
useLayoutEffect(() => {
document.documentElement.scrollTo(0, 0);
}, [location.pathname]);
return children
}
const Component = ({title}) => {
return (
<div>
<p style={{paddingTop: '150vh'}}>{title}</p>
</div>
)
}
const App = () => {
return (
<BrowserRouter>
<Wrapper>
<p>Scroll the bottom to change pages</p>
<Routes>
<Route path="/" element={<Component title="Home"/>} />
<Route path="/about" element={<Component title="About"/>} />
<Route path="/product" element={<Component title="Product"/>} />
</Routes>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/product">Product</Link>
</Wrapper>
</BrowserRouter>
)
}
export default App
this article resolves this issue See it -> https://www.matthewhoelter.com/2022/04/02/how-to-scroll-to-top-on-route-change-with-react-router-dom-v6.html
make ScrollToTop component
and then add this code init
import { useLocation } from "react-router-dom";
export default function ScrollToTop() {
const { pathname } = useLocation();
useEffect(() => {
// "document.documentElement.scrollTo" is the magic for React Router Dom v6
document.documentElement.scrollTo({
top: 0,
left: 0,
behavior: "instant", // Optional if you want to skip the scrolling animation
});
}, [pathname]);
return null;
}
and then import it in your App.js and now your issue is resolved
see img
const scrollToPosition = (top = 0) => {
try {
/**
* Latest API
*/
window.scroll({
top: top,
left: 0,
behavior: "smooth",
});
} catch (_) {
/**
* Fallback
*/
window.scrollTo(0, top);
}
};
You can use the above code to scroll top.
const didMount = useDidMount();
const router = useRouter();
const { asPath } = router;
useEffect(() => {
if (didMount) {
scrollToPosition();
}
}, [asPath]);
And add the above code to the top parent component.
The window function cannot be accessed in newer versions of react, it is better to use the useRef Hook.
const myRef = useRef<any>(null);
const executeScroll = () => myRef.current.scrollIntoView({inline: "center"});
useEffect(() => {
executeScroll();
}, [location.pathname]);
// YOUR COMPONENTS CODE
// I have my toolbar as the ref
<Toolbar ref={myRef}/>
This will scroll when using the useNavigator and the pathname changes.

Adding Preloader in React Application

I want add a preloader in my react application. The reason is, my application needs much time to load. So, I want that When all my application contents is fully ready to be load, it will be rendered automatically. A preloader will be rendering as long as my application takes time to get ready to be loaded. Is it possible to do?
I need help.
This is me App code given below:-
import React from 'react';
import Navbar from './Navbar'
import Home from './Home';
import About from './About';
import Services from './Services';
import Skills from './Skills';
import Contact from './Contact';
import Footer from './Footer';
import Reset from './Reset';
function App() {
return (
<>
<Reset />
<Navbar />
<Home />
<About />
<Services />
<Skills />
<Contact />
<Footer />
</>
);
}
export default App;
This is my Index.js code given below:-
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import Preloader from './Preloader'
ReactDOM.render(
<App/>
,document.getElementById('root')
);
Depending on what you want to achieve you have many options on doing this. That is the goal of using frameworks like React.
My advice is, separate the loading of data( API calls etc.) from the loading of UI. Use async methods for loading the data where you can do that. I see that you are using functional components, so look into react hooks and generating the data using states.
You have a way of setting a default value to a state so everything could render independently from the data generation. Later when the state is set to your data the site will render automatically with the new data.
Specifically to setting a preload ui you can check this post:
React - Display loading screen while DOM is rendering?
We usually make an API call and until the data is ready we show a loader. An SVG Loader or any other loader.
You basically need to set three states to maintain loading, error and your data:
Use the following setup this will be helpful in your project. Also visit my github project to get Loader Code from API and Loader
function App() {
const [tours, setTours] = useState([]);
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);
/*--- I am using fetch API here
useEffect(() => {
setLoading(true);
fetch(url)
.then((response) => {
if (response.status >= 200 && response.status < 300) {
return response.json();
} else {
throw new Error("Could not fetch data");
}
})
.then((tours) => {
setLoading(false);
setTours(tours);
})
.catch((err) => console.log(err));
}, []);
---*/
const fetchTours = async () => {
try {
const response = await fetch(url);
const tours = await response.json();
setLoading(false);
setTours(tours);
} catch (error) {
setLoading(false);
setError(true);
}
};
useState(() => {
setLoading(true);
fetchTours();
}, []);
// Functionality 1: Not Interested Button click
const handleBtnClick = (id) => {
const updatedTours = tours.filter((tour) => tour.id !== id);
setTours(updatedTours);
};
// Functionality 2: Refresh Button click
const handleRefresh = () => {
setLoading(true);
fetchTours();
};
// Let us do conditional rendering
if (loading) {
return (
<div style={{ textAlign: "center", margin: "2rem 0" }}>
<Loader />
</div>
);
}
if (error) {
return <p>Error ...</p>;
}
return (
<section>
<p className="our-tours">
{tours.length > 0 ? (
"Our Tours"
) : (
<div>
<p>No Tours Left</p>
<button className="btn" onClick={handleRefresh}>
Refresh
</button>
</div>
)}{" "}
</p>
<main className="App">
{tours.length > 0 && (
<Tours tours={tours} handleClick={handleBtnClick} />
)}
</main>
</section>
);
}
export default App;
There are three scenarios:
Initially our loading is true and we show our loader.
When the data has successfully arrived, we start showing the data and hide our Loader.
When there is an error in our API call, we show the error message.
The above setup works in all cases :)
If you're using reactjs, you need to make a component so try this:
import { useEffect } from "react";
import { Rings } from "react-loader-spinner";
const Loader = () => {
useEffect(() => {
window.onload=()=>{
const preloader = document.querySelector(".preloader");
preloader.remove();
}
});
return <LoaderFile/>
// which have your preloader html and having class is `.preloader`
};
export default Loader;
In App.js File
const App = () => {
return (
<>
<Loader /> // Add Loader Component here
<Router>
<Routes>
<Route path="/" element={<Navigation />}>
<Route index element={<Main />} />
</Route>
</Routes>
</Router>
</>
);
};

How to work with setInterval to trigger an event? JavaScript/React-toastify

I have a redux store that contains an object that looks like
rooms: {
room01 : { timestamp: 10}
room02 : { timestamp: 10}
}
When a user clicks on a button the timestamp is set to 10 (via dispatch). If there is a timestamp I count down to 0 and then set a Notification using react-toast across the app.
The problem is I don't have roomId available on Notification component because Notification component has to be placed at app root otherwise it's get unmounted and my Notification() logic doesn't work. (I could access the rooms in Notification or App but it comes in an array for eg ['room01', 'room02'] which is also in redux but how do I select both rooms and access their timestamp as well as run the function to count down?).
Basically I need to check if there is timestamp in redux store for each room and if there is, count down to 0 and display notification with the roomId. The notification/setinterval should work while navigating to different pages.
My app component
import React from 'react';
import { Route, Switch, BrowserRouter } from 'react-router-dom';
import Home from './Home';
import 'react-toastify/dist/ReactToastify.css';
import Notification from '../features/seclusion/Notification';
const App = () => {
return (
<div>
<Notification /> // if I pass in room id like so roomId={'room02'} I cant get it to work for one room
<BrowserRouter>
<Switch>
<Route exact path="/room/:id" component={Room} />
<Route exact path="/" component={Home} />
</Switch>
</BrowserRouter>
</div>);
};
export default App;
import React, { useState, useEffect } from 'react';
import { useSelector } from 'react-redux';
import 'react-toastify/dist/ReactToastify.css';
import { ToastContainer, toast, Slide } from 'react-toastify';
import moment from 'moment';
export default function Notification() {
const timestamp = useSelector(state => state.rooms); // need to get timestamp for room01 and room02
const [timestamp, setTimestamp] = useState(null);
const [timerId, setTimerId] = useState(null);
const notify = () => {
toast(<div>alert</div>,
{
position: "top-center",
});
};
useEffect(() => {
if (timestamp) {
const id = setInterval(() => {
setTimestamp((timestamp) => timestamp - 1)
}, 1000)
setTimerId(id);
}
return () => {
clearInterval(timerId);
};
}, [timestamp]);
useEffect(() => {
if(timestamp === 0){
notify();
clearInterval(timerId);
}
}, [timestamp])
return (
<ToastContainer
newestOnTop={true}
transition={Slide}
autoClose={false}
/>
);
}
You could do the following among other approaches, but i think the following is the best because it makes the Notification component more reusable, and also it makes better use of the separation of responsibilities, makes your code easier to read, and most importantly is aligned with the declarative mindset of React.
const App = () => {
const rooms = state.rooms // this is not redux syntax but i will leave that to you
return (
<div>
{Object.entries(rooms).map(([roomId, roomDetails]) => {
const {timestamp} = roomDetails;
// Obviously you now need to modify your Notification component to handle these props
return <Notification
timestamp={timestamp}
roomId={roomId} // actually its better to create the Notification component without the roomId prop and use the roomId to induce the message prop, this makes Notification component more reusable across other components
key={`${roomId}-${timestamp}`}
message="You might send message here instead of doing that inside the Notification component"
/>
// You might be interested to rename Notification to DelayedNotification or something else
}}
<BrowserRouter>
<Switch>
<Route exact path="/room/:id" component={Room} />
<Route exact path="/" component={Home} />
</Switch>
</BrowserRouter>
</div>);
};

How can I change this class base higher order component into a functional component?

I have already created a HOC in my react app following this, and its working fine. However i was wondering if there is a way to create a HOC as functional component(With or without state)??? since the given example is a class based component.
Tried to find the same over web but couldn't get anything. Not sure if thats even possible?? Or right thing to do ever??
Any leads will be appreciated :)
I agree with siraj, strictly speaking the example in the accepted answer is not a true HOC. The distinguishing feature of a HOC is that it returns a component, whereas the PrivateRoute component in the accepted answer is a component itself. So while it accomplishes what it set out to do just fine, I don't think it is a great example of a HOC.
In the functional component world, the most basic HOC would look like this:
const withNothing = Component => ({ ...props }) => (
<Component {...props} />
);
Calling withNothing returns another component (not an instance, that's the main difference), which can then be used just like a regular component:
const ComponentWithNothing = withNothing(Component);
const instance = <ComponentWithNothing someProp="test" />;
One way to use this is if you want to use ad-hoc (no pun intended lol) context providers.
Let's say my application has multiple points where a user can login. I don't want to copy the login logic (API calls and success/error messages) across all these points, so I'd like a reusable <Login /> component. However, in my case all these points of login differ significantly visually, so a reusable component is not an option. What I need is a reusable <WithLogin /> component, which would provide its children with all the necessary functionality - the API call and success/error messages. Here's one way to do this:
// This context will only hold the `login` method.
// Calling this method will invoke all the required logic.
const LoginContext = React.createContext();
LoginContext.displayName = "Login";
// This "HOC" (not a true HOC yet) should take care of
// all the reusable logic - API calls and messages.
// This will allow me to pass different layouts as children.
const WithLogin = ({ children }) => {
const [popup, setPopup] = useState(null);
const doLogin = useCallback(
(email, password) =>
callLoginAPI(email, password).then(
() => {
setPopup({
message: "Success"
});
},
() => {
setPopup({
error: true,
message: "Failure"
});
}
),
[setPopup]
);
return (
<LoginContext.Provider value={doLogin}>
{children}
{popup ? (
<Modal
error={popup.error}
message={popup.message}
onClose={() => setPopup(null)}
/>
) : null}
</LoginContext.Provider>
);
};
// This is my main component. It is very neat and simple
// because all the technical bits are inside WithLogin.
const MyComponent = () => {
const login = useContext(LoginContext);
const doLogin = useCallback(() => {
login("a#b.c", "password");
}, [login]);
return (
<WithLogin>
<button type="button" onClick={doLogin}>
Login!
</button>
</WithLogin>
);
};
Unfortunately, this does not work because LoginContext.Provider is instantiated inside MyComponent, and so useContext(LoginContext) returns nothing.
HOC to the rescue! What if I added a tiny middleman:
const withLogin = Component => ({ ...props }) => (
<WithLogin>
<Component {...props} />
</WithLogin>
);
And then:
const MyComponent = () => {
const login = useContext(LoginContext);
const doLogin = useCallback(() => {
login("a#b.c", "password");
}, [login]);
return (
<button type="button" onClick={doLogin}>
Login!
</button>
);
};
const MyComponentWithLogin = withLogin(MyComponent);
Bam! MyComponentWithLogin will now work as expected.
This may well not be the best way to approach this particular situation, but I kinda like it.
And yes, it really is just an extra function call, nothing more! According to the official guide:
HOCs are not part of the React API, per se. They are a pattern that emerges from React’s compositional nature.
Definitely you can create a functional stateless component that accepts component as an input and return some other component as an output, for example;
You can create a PrivateRoute component that accepts a Component as a prop value and returns some other Component depending on if user is authenticated or not.
If user is not authenticated(read it from context store) then you redirect user to login page with <Redirect to='/login'/>else you return the component passed as a prop and send other props to that component <Component {...props} />
App.js
const App = () => {
return (
<Switch>
<PrivateRoute exact path='/' component={Home} />
<Route exact path='/about' component={About} />
<Route exact path='/login' component={Login} />
<Route exact path='/register' component={Register} />
</Switch>
);
}
export default App;
PrivateRoute.jsx
import React, { useContext , useEffect} from 'react';
import { Route, Redirect } from 'react-router-dom'
import AuthContext from '../../context/auth/authContext'
const PrivateRoute = ({ component: Component, ...rest }) => {
const authContext = useContext(AuthContext)
const { loadUser, isAuthenticated } = authContext
useEffect(() => {
loadUser()
// eslint-disable-next-line
}, [])
if(isAuthenticated === null){
return <></>
}
return (
<Route {...rest} render={props =>
!isAuthenticated ? (
<Redirect to='/login'/>
) : (
<Component {...props} />
)
}
/>
);
};
export default PrivateRoute;
Higher Order Components does not have to be class components, their purpose is to take a Component as an input and return a component as an output according to some logic.
The following is an over simplified example of using HOC with functional components.
The functional component to be "wrapped":
import React from 'react'
import withClasses from '../withClasses'
const ToBeWrappedByHOC = () => {
return (
<div>
<p>I'm wrapped by a higher order component</p>
</div>
)
}
export default withClasses(ToBeWrappedByHOC, "myClassName");
The Higher Order Component:
import React from 'react'
const withClasses = (WrappedComponent, classes) => {
return (props) => (
<div className={classes}>
<WrappedComponent {...props} />
</div>
);
};
export default withClasses;
The component can be used in a different component like so.
<ToBeWrappedByHOC/>
I might be late to the party but here is my two-cent regarding the HOC
Creating HOC in a true react functional component way is kind of impossible because it is suggested not to call hook inside a nested function.
Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls. (If you’re curious, we’ll explain this in-depth below.)
Rules of Hooks
Here is what I have tried and failed
import React, { useState } from "react";
import "./styles.css";
function Component(props) {
console.log(props);
return (
<div>
<h2> Component Count {props.count}</h2>
<button onClick={props.handleClick}>Click</button>
</div>
);
}
function Component1(props) {
console.log(props);
return (
<div>
<h2> Component1 Count {props.count}</h2>
<button onClick={props.handleClick}>Click</button>
</div>
);
}
function HOC(WrapperFunction) {
return function (props) {
const handleClick = () => {
setCount(count + 1);
};
const [count, setCount] = useState(0);
return (
<WrapperFunction handleClick={handleClick} count={count} {...props} />
);
}
}
const Comp1 = HOC((props) => {
return <Component {...props} />;
});
const Comp2 = HOC((props) => {
return <Component1 {...props} />;
});
export default function App() {
return (
<div className="App">
<Comp1 name="hel" />
<Comp2 />
</div>
);
}
CodeSandBox
Even though the code works in codesandbox but it won't run in your local machine because of the above rule, you should get the following error if you try to run this code
React Hook "useState" cannot be called inside a callback
So to go around this I have done the following
import "./styles.css";
import * as React from "react";
//macbook
function Company(props) {
return (
<>
<h1>Company</h1>
<p>{props.count}</p>
<button onClick={() => props.increment()}>increment</button>
</>
);
}
function Developer(props) {
return (
<>
<h1>Developer</h1>
<p>{props.count}</p>
<button onClick={() => props.increment()}>increment</button>
</>
);
}
//decorator
function HOC(Component) {
// return function () {
// const [data, setData] = React.useState();
// return <Component />;
// };
class Wrapper extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
handleClick = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<Component count={this.state.count} increment={this.handleClick} />
);
}
}
return Wrapper;
}
const NewCompany = HOC(Company);
const NewDeveloper = HOC(Developer);
export default function App() {
return (
<div className="App">
<NewCompany name={"Google"} />
<br />
<NewDeveloper />
</div>
);
}
CodeSandbox
I think for functional component this works fine
import {useEffect, useState} from 'react';
// Target Component
function Clock({ time }) {
return <h1>{time}</h1>
}
// HOC
function app(C) {
return (props) => {
const [time, setTime] = useState(new Date().toUTCString());
useEffect(() => {
setTimeout(() => setTime(new Date().toUTCString()), 1000);
})
return <C {...props} time={time}/>
}
}
export default app(Clock);
You can test it here: https://codesandbox.io/s/hoc-s6kmnv
Yes it is possible
import React, { useState } from 'react';
const WrapperCounter = OldComponent =>{
function WrapperCounter(props){
const[count,SetCount] = useState(0)
const incrementCounter = ()=>{
SetCount(count+1)
}
return(<OldComponent {...props} count={count} incrementCounter={incrementCounter}></OldComponent>)
}
return WrapperCounter
}
export default WrapperCounter
import React from 'react';
import WrapperCounter from './WrapperCounter';
function CounterFn({count,incrementCounter}){
return(
<button onClick={incrementCounter}>Counter inside functiona component {count}</button>
)
}
export default WrapperCounter(CounterFn)

Categories