How can I know my current route in react-navigation 5? - javascript

I am using this https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html to access my navigation from any source, my file look as follow:
import { createRef } from 'react';
export const navigationRef = createRef();
export function navigate(name, params) {
return navigationRef.current?.navigate(name, params);
}
export function goBack() {
return navigationRef.current?.goBack();
}
export function getRootState() {
return navigationRef.current?.getRootState();
}
This is perfect for my #navigation/drawer, which is outside my stack navigation.
Only one problem the last method is not synchronized and I want to have an active state on my item menu that is the current route.
How is that possible with react navigation 5?

I am using the following approach to get the current route name in react-navigation v5.
https://reactnavigation.org/docs/navigation-prop/#dangerouslygetstate
const {index, routes} = this.props.navigation.dangerouslyGetState();
const currentRoute = routes[index].name;
console.log('current screen', currentRoute);

The NavigationContainer has onStateChange prop, useful for this case, check react-navigation docs Screen Tracking for analytics and if you need access without navigation prop see Navigating without the navigation prop
I share the code to get only active routeName
function App(){
const routeNameRef = React.useRef();
// Gets the current screen from navigation state
const getActiveRouteName = (state)=> {
const route = state.routes[state?.index || 0];
if (route.state) {
// Dive into nested navigators
return getActiveRouteName(route.state);
}
return route.name;
};
return (<NavigationContainer
onStateChange={(state) => {
if (!state) return;
//#ts-ignore
routeNameRef.current = getActiveRouteName(state);
}}
>
...
</NavigationContainer>)
}

If you want to know the current screen from a component you can also use this:
export const HomeScreen = ({ navigation, route }) => {
console.log(route.name);
return (
{...}
);
};

It is possible to get this from the navigationRef attached to the navigation container. Where navigationRef is a ref.
export const navigationRef = React.createRef()
and
<NavigationContainer
ref={navigationRef}
>
<Navigator />
</NavigationContainer>
Then use: const currentRouteName = navigationRef.current.getCurrentRoute().name to get the current route name.
Alternatively in a functional component you can useRef const navigationRef = React.useRef()

There is a util function called getFocusedRouteNameFromRoute(route) which the docs recommends.
BUT - it seems its working only for child screen, so I defined the following function to get the active route name:
const getCurrentRouteName = (navigation, route) => {
if (route.state)
return getFocusedRouteNameFromRoute(route);
return route.name;
};

This works for me. In navigationRef.js
let navigator;
export const setNavigator = (nav) => {
navigator = nav;
};
export const getCurrentRoute = () => {
const route = navigator.getCurrentRoute();
return route.name;
};
This can be referred from any source like this
import { getCurrentRoute } from '../navigationRef';
const currentScene = getCurrentRoute();

Related

Accessing multiple easy-peasy stores from single component

I'm trying to access 2 different stores in a single component, but worry that perhaps the architecture of my app may need to change as easy-peasy may not have this functionality.
I have a GlobalStore
import { createStore } from 'easy-peasy';
const globalModel = {
menuOpen: false,
toggleMenu: action((state, payload) => {
state.menuOpen = payload;
}),
};
const GlobalStore = createStore(globalModel);
export default GlobalStore;
Just for this example, I'll use a single state and action used in the store to define whether the navigation menu is open or not.
The GlobalStore appears at the top level of my app in my App.js file.
import React from 'react';
import { StoreProvider } from 'easy-peasy';
import GlobalStore from './store/GlobalStore';
const App = () => {
return (
<StoreProvider store={GlobalStore}>
</StoreProvider>
);
};
export default App;
Now, further down the tree, I have another store SearchStore that dictates which view is active in the component.
import { createStore } from 'easy-peasy';
import { action } from 'easy-peasy';
const searchModel = {
view: 'filter',
setView: action((state, payload) => {
state.view = payload;
}),
};
const SearchStore = createStore(searchModel);
export default SearchStore;
The issue I have now is that in a component that I need to be able to access both stores to update the view with the setView action in the SearchStore and get the value of menuOpen from the GlobalStore but cannot access both concurrently.
The example I have in a component is that I have a styled component that when clicked calls the action setView but its position is also defined by whether the menuOpen is true or not. but obviously, if I try and get the state of menuOpen it will be undefined as it does not exist in SearchStore
const Close = styled.span`
$(({ menuOpen }) => menuOpen ? `
// styles go here
` : `` }
`;
const setView = useStoreActions((action) => action.setView);
const menuOpen = useStoreState((state) => state.menuOpen);
<Close menuOpen={menuOpen} onClick={() => setView('list')}>
Is this possible? Any help would be much appreciated.
Alternative 1: extending the global store
To access both store (via the useStoreState/Actions from the StoreProvider), you could nest both "sub" stores into the GlobalStore:
// SearchModel.js
import { action } from 'easy-peasy';
const searchModel = {
view: 'filter',
setView: action((state, payload) => {
state.view = payload;
}),
};
export default searchModel;
// MenuModel.js
import { action } from 'easy-peasy';
const menuModel = {
isOpen: false,
toggle: action((state, payload) => {
state.isOpen = !state.isOpen;
}),
};
export default menuModel;
// GlobalStore.js
import { createStore } from 'easy-peasy';
import menu from './MenuhModel';
import search from './SearchModel';
const globalModel = {
menu,
search,
};
const GlobalStore = createStore(globalModel);
export default GlobalStore;
This way, you can access both stores at your convenience, using the hooks:
const searchState = useStoreState((state) => state.search);
const menuState = useStoreState((state) => state.menu);
const searchActions = useStoreActions((action) => action.search);
const menuActions = useStoreActions((action) => action.menu);
Alternative 2: useLocalStore()
If you do not want to extend the global store, you could create a local store, by using the useLocalStore():
function Menu() {
const [state, actions] = useLocalStore(() => ({
isOpen: false,
toggle: action((state, payload) => {
state.isOpen = !state.isOpen;
}),
}));
return (
<div>
{state.isOpen && <MenuItems />}
<button onClick={() => actions.toggle()}>Open menu</button>
</div>
);
}
However, the drawback of this approach, is that the state is not global and only available at the component-level.
You could however get around this, by creating your own provider - but then again, alternative 1 would probably be the path of least resistance.

How to change scroll behavior while going back in next js?

I fetch a list of posts in index js like this :
const Index = (props) => {
return (
<div>
{props.posts.map((each) => {
return (
<Link scroll={false} as={`/post/${each.id}`} href="/post/[id]" key={each.id}>
<a>
<h1>{each.title}</h1>
</a>
</Link>
);
})}
</div>
);
};
export async function getStaticProps() {
const url = `https://jsonplaceholder.typicode.com/posts`;
const res = await axios.get(url);
return {
props: { posts: res.data }
};
}
And when user clicks on any link it goes to post page which is :
function post({ post }) {
return (
<h1>{post.id}</h1>
);
}
export async function getServerSideProps({ query }) {
const { id } = query;
const res = await Axios.get(`https://jsonplaceholder.typicode.com/posts/${id}`);
return {
props: { post: res.data}
};
}
The problem is when I click back the scroll position resets to top and it fetches all posts .
I included scroll={false} in Link but it doesn't work .
How can I prevent scroll resetting when user clicks back from the post page ?
Next.js in fact has built-in support for restoring scroll position when back to the previous page. We can simply enable it by editing the next.config.js:
module.exports = {
experimental: {
scrollRestoration: true,
},
}
scroll={false} doesn't maintain the scroll of the previous page; it doesn't change the scroll at all which means the scroll would be that of the page you are linking from. You can use scroll={false} to override the default behavior of setting the scrollY to 0, so you can implement your own behavior.
Here's how I implemented restoring the scroll position. This is very similar to Max william's answer, but using useRef instead of useState. We are using useRef instead of useState because useRef does not cause a re-render whenever its value is mutated, unlike useState. We are going to be updating the value to the current scroll position every time the scroll is changed by the user, which would mean a ton of useless re-renders if we were to use useState.
First, define a UserContext component to easily pass the scroll data from the _app.js component to wherever you need:
import { createContext } from 'react';
const UserContext = createContext();
export default UserContext;
Then, in your _app.js component, wrap your pages with the UserContext and create a useRef attribute to store the scroll position.
import { useRef } from 'react';
import UserContext from '../components/context'
function MyApp({ Component, pageProps }) {
const scrollRef = useRef({
scrollPos: 0
});
return (
<Layout>
<UserContext.Provider value={{ scrollRef: scrollRef }}>
<Component {...pageProps} />
</UserContext.Provider>
</Layout>
)
}
export default MyApp
Then inside whichever page component you are wanting to restore the scroll position (that is, the page that you want to return to and see the same scroll position as when you left), you can put this code to set the scroll position of the page and bind a scroll event to a function to update the stored scroll position.
import UserContext from '../components/context'
import { useContext } from 'react';
export default function YourPageComponent() {
const { scrollRef } = useContext(UserContext);
React.useEffect(() => {
//called when the component has been mounted, sets the scroll to the currently stored scroll position
window.scrollTo(0, scrollRef.current.scrollPos);
const handleScrollPos = () => {
//every time the window is scrolled, update the reference. This will not cause a re-render, meaning smooth uninterrupted scrolling.
scrollRef.current.scrollPos = window.scrollY
};
window.addEventListener('scroll', handleScrollPos);
return () => {
//remove event listener on unmount
window.removeEventListener('scroll', handleScrollPos);
};
});
return (
//your content
)
}
The last little thing is to use scroll={false} on your Link component that links back to YourPageComponent. This is so next.js doesn't automatically set the scroll to 0, overriding everything we've done.
Credit to Max william's answer to the majority of the structure, my main change is using useRef. I also added some explanations, I hope it's helpful!
I solved the problem with the help of context and window scroll position like this :
import UserContext from '../context/context';
function MyApp({ Component, pageProps }) {
const [ scrollPos, setScrollPos ] = React.useState(0);
return (
<UserContext.Provider value={{ scrollPos: scrollPos, setScrollPos: setScrollPos }}>
<Component {...pageProps} />
</UserContext.Provider>
);
}
export default MyApp;
index js file :
import Link from 'next/link';
import UserContext from '../context/context';
import { useContext } from 'react';
import Axios from 'axios';
export default function Index(props) {
const { scrollPos, setScrollPos } = useContext(UserContext);
const handleScrollPos = () => {
setScrollPos(window.scrollY);
};
React.useEffect(() => {
window.scrollTo(0, scrollPos);
}, []);
React.useEffect(() => {
window.addEventListener('scroll', handleScrollPos);
return () => {
window.removeEventListener('scroll', handleScrollPos);
};
}, []);
if (props.err) {
return <h4>Error bro</h4>;
}
return (
<div>
{props.res.map((each) => {
return (
<div key={each.id}>
<Link scroll={true} as={`/post/${each.id}`} href="/post/[id]">
{each.title}
</Link>
</div>
);
})}
</div>
);
}
export async function getServerSideProps() {
let res;
let err;
try {
res = await Axios.get('https://jsonplaceholder.typicode.com/posts');
err = null;
} catch (e) {
err = 'Error bro';
res = { data: [] };
}
return {
props: {
res: res.data,
err: err
}
};
}
post js file :
import Axios from 'axios';
function Post(props) {
if (props.err) {
return <h4>{props.err}</h4>;
}
return <h1>{props.post.title}</h1>;
}
export async function getServerSideProps(ctx) {
const { query } = ctx;
let err;
let res;
try {
res = await Axios.get(`https://jsonplaceholder.typicode.com/posts/${query.id}`);
err = null;
} catch (e) {
res = { data: [] };
err = 'Error getting post';
}
return {
props: {
post: res.data,
err: err
}
};
}
export default Post;
So when you click back from post js page , the first useEffect in index js will run and you will be scrolled to that position .
Also after that the second useEffect will capture the user's scroll position by listening to the scroll event listener so it will always save the latest scroll y position in context so next time you comeback to index js the first useEffect will run and set scroll position to that value in context .

Rest API response not updating until page is refreshed

I've got component that displays contact information from a dealer as chosen by a user. To be more specific, a user selects their location, setting a cookie which then is used to define the API call. I pull in the contact information of the dealer in that location using Axios, store it in a context, and then display the information as necessary through several components: the header, a "current location" component etc.
The problem that I'm currently running into is that the contact information, as displayed in the Header for example, doesn't update until a user performs a hard refresh of the page, so, assuming the default text of the button is something like "Find A Dealer", once a dealer is selected, the button label should say the name of the dealer the user has selected. At present, it isn't working that way. Below is the code for the Header component, and my ApiContext.
ApiContext.tsx
import React, { createContext } from 'react';
import axios from 'axios';
import { makeUseAxios } from 'axios-hooks';
import { useCookie } from 'hooks/use-cookie';
const contextObject = {} as any;
export const context = createContext(contextObject);
const useAxios = makeUseAxios({
axios: axios.create({ baseURL: process.env.GATSBY_API_ENDPOINT }),
});
export const ApiContext = ({ children }: any) => {
const [cookie] = useCookie('one-day-location', '1');
const [{ data }] = useAxios(`${cookie}`);
const { Provider } = context;
return <Provider value={data}>{children}</Provider>;
};
Header.tsx
import React, { ReactNode, useContext, useEffect, useState } from 'react';
import Logo from 'assets/svg/logo.svg';
import css from 'classnames';
import { Button } from 'components/button/Button';
import { Link } from 'components/link/Link';
import { MenuIcon } from 'components/menu-icon/MenuIcon';
import { context } from 'contexts/ApiContext';
import { NotificationBar } from '../notification-bar/NotificationBar';
import s from './Header.scss';
import { MainNav } from './navigation/MainNav';
interface HeaderProps {
navigationContent: ReactNode;
}
export const Header = ({ navigationContent }: HeaderProps) => {
const [scrolled, setScrolled] = useState(false);
const [open, setOpen] = useState(false);
const data = useContext(context);
const buttonLabel = data ? data.name : 'Find a Dealer';
const buttonLink = data ? `tel:${data.phone}` : '/find-a-dealer';
useEffect(() => {
const handleScroll = () => {
const isScrolled = window.scrollY > 10;
if (isScrolled !== scrolled) {
setScrolled(!scrolled);
}
};
document.addEventListener('scroll', handleScroll, { passive: true });
return () => {
document.removeEventListener('scroll', handleScroll);
};
}, [scrolled]);
return (
<>
<NotificationBar notificationContent={navigationContent} />
<header className={scrolled ? css(s.header, s.header__scrolled) : s.header}>
<nav className={s.header__navigation}>
<ul className={s.header__container}>
<li className={s.header__logo}>
<Link to="/" className={s.header__link}>
<Logo />
</Link>
</li>
<li className={s.header__primary}>
<MainNav navigationItems={navigationContent} />
</li>
<li className={s.header__utility}>
<Button href={buttonLink}>{buttonLabel}</Button>
</li>
<li className={s.header__icon}>
<MenuIcon onClick={() => setOpen(!open)} />
</li>
</ul>
</nav>
</header>
</>
);
};
Here is a screenshot of my console logs, where I'm logging what is returned from data in the ApiContext.
Any suggestions on this would be greatly appreciated, even if it means completely refactoring the way that I'm using this. Thanks!
You are almost there, your ApiContext looks good, it retrieves the information and populates the context, however, what you are missing is a useState to trigger an update to force the re-hydration of your buttons.
What is happening is that your context never updates the data constant. At the first rendering is empty, once your request is done and the context is full but your button is never being updated. Something like this may work for you:
const data = useContext(context);
const [newData, setNewData] = useState(data);
const buttonLabel = newData? newData.name : 'Find a Dealer';
const buttonLink = newData? `tel:${newData.phone}` : '/find-a-dealer';
You may need to adapt the code a bit to fit your requirements, nevertheless, you may keep the idea, which is creating a state with your retrieved data.
You can create a useEffect to control when the data changes and populate the state if you wish:
useEffect(()=>{
setNewData(data)
}, [data])
After a lot of digging, I was able to figure this out myself.
Using the recommendations from Ferran as a base, I decided that it would be best to rehydrate the components displaying the contact info from a state, but as I'm using this context in multiple components, I needed to have the state update globally. I moved away from makeUseAxios, to a traditional axios call. The dealer ID is then stored in the state and used in the call. I also created the changeDealer const, which I can pass through the context, and which updates the state:
ApiContext.tsx
import React, { createContext, useEffect, useState } from 'react';
import axios from 'axios';
const contextObject = {} as any;
export const context = createContext(contextObject);
export const ApiContext = ({ children }: any) => {
const [dealerId, setDealerId] = useState(`1`);
useEffect(() => {
axios.get(`${process.env.GATSBY_API_ENDPOINT}/${dealerId}`).then((res) => setDealerId(res.data));
}, [dealerId]);
const changeDealer = (value: any) => {
setDealerId(value);
};
const { Provider } = context;
return <Provider value={{ data: dealerId, changeDealer: changeDealer }}>{children}</Provider>;
};
Then if, for example, I have a button that updates the dealer info, I import the context to the component and pass changeDealer through the it:
import { context } from 'contexts/ApiContext';
const { changeDealer } = useContext(context);
I can then attach it to a button like so:
<Link to="/" onClick={() => changeDealer(dealer.id)}>
Set Location
</Link>
This updates the state globally, changing the contact information across all the components that display it. I will be storing the data in a localStorage item, allowing the data to persist after a page refresh.

Get query string value in React JS

I am having URL as http://example.com/callback?code=abcd
I need to fetch value of code.
Below is my code:
import React from 'react';
import { useEffect } from 'react';
const Callback = () => {
useEffect(() => {
console.log("hiii");
}, []);
return (
<React.Fragment>
Callback
</React.Fragment>
);
};
export default Callback;
Please confirm how can I fetch that.
Thanks in advance.
Probably the best way is to use the useParams hook because you have a functional component. Read from the documentation as the following:
useParams returns an object of key/value pairs of URL parameters. Use it to access match.params of the current <Route>.
I would suggest the following:
import React from 'react'
import { useParams } from 'react-router-dom'
const Callback = () => {
let { code } = useParams()
console.log({ code });
return (
<React.Fragment>
Callback
</React.Fragment>
)
};
+1 from documentation:
You need to be using React >= 16.8 in order to use any of these hooks!
use this library 'query-string'
and use as
import queryString from 'query-string';
in constructor
constructor(props) {
const { location: { search } } = props;
const parsed = queryString.parse(search);
this.state = {
code: parsed.code,
}
}
hope it will solve your problem !
Try this
http://example.com/callback?code=abcd
// ReactJS
import React from "react";
import { useLocation } from "react-router-dom";
const MyComponent = () => {
const search = useLocation().search;
const code = new URLSearchParams(search).get("code");
console.log(code); //abcd
}
// VanillaJS
const code = window.location.search.split("=")[1];
console.log(code); //abcd
You can use the URLSearchParams interface to fetch the query string of a URL.
https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
const queryParams = new URLSearchParams(window.location.search);
const code = queryParams.get("code");
First at App.js you should have react-router-dom
import { Route, Switch } from "react-router-dom";
Then inside switch you can define route parameters like in your case
<Route exact path="/callback/:code" component={YourComponentsName} />
At the components file you can get the parameters from the props
Functional Component
const code = props.match.params.code
Class Component
const code = this.props.match.params.code
Or next approach
const code = new URLSearchParams(this.props.location.search);
const code = query.get('code')
console.log(code)//abcd
You need to use a hook...
useEffect(() => {
let urlParams = new URLSearchParams(window.location.search);
console.log(urlParams.code || "empty");
}, []);

React: How to use one variable in one component when it is imported to another component

import React, { useEffect, useState } from 'react';
import { Card } from 'components/Card';
import { dateFilter } from 'helpers';
import Chart from 'chart.js';
import 'chartjs-chart-matrix';
import chroma from 'chroma-js';
import moment from 'moment';
const WeeklyTrafficCard = (props) => {
const { start, end, data, store } = props;
const capacity = store && store.capacity;
var numberOfweeks = 0; //representing how many weeks back
const dateArray = [];
var today = moment();
while (numberOfweeks < 10) {
var from_date = today.startOf('week').format('MM/DD/YY');
var to_date = today.endOf('week').format('MM/DD/YY');
var range = from_date.concat(' ','-',' ',to_date);
dateArray.push(range);
today = today.subtract(7, 'days');
numberOfweeks++;
//console.log(dateArray);
}
const [each_daterange, setDateRange] = useState();
I have this Component called WeeklyTrafficCard and I want to use the variable, each_daterange, in another component, which imported WeeklyTrafficCard as below to send the get request, clearly I cannot use each_daterange directly right here, how I can work around it?
import React, { useContext, useEffect, useState } from 'react';
import { WeeklyTrafficCard } from './WeeklyTrafficCard';
import { AppContext } from 'contexts/App';
import { API_URL } from 'constants/index.js';
import { todayOpen, todayClose } from 'helpers';
import moment from 'moment';
const WeeklyTrafficCardContainer = (props) => {
const { API } = useContext(AppContext);
const { store = {} } = props;
const [data, setData] = useState([]);
const open = todayOpen(store.hours, store.timezone);
const close = todayClose(store.hours, store.timezone);
useEffect(() => {
async function fetchData() {
const result = await API.get(`${API_URL}/api/aggregates`, {
params: {
each_daterange,
every: '1h',
hourStart: 13,
hourStop: 4
},
});
You should use a useEffect(prop drilling) to pass your variable in your parent:
import React, { Component } from "react";
import { render } from "react-dom";
import "./style.css";
const App = () => {
const [myVar, setMyVar] = React.useState('');
return (
<div>
<Child setMyVar={setMyVar} />
{myVar}
</div>
);
};
const Child = ({setMyVar}) => {
const myChildVar = "Hello world !"
React.useEffect( () => setMyVar(myChildVar),[]);
return <div> This is the child</div>
}
render(<App />, document.getElementById("root"));
Here is the repro on stackblitz
Understanding of the Problem
You want to pass data up to the parent from the child.
Manage each_daterange in the parent:
Instead of creating your useState variable each_daterange in the child you can declare it in the parent and pass down it's setter function. For instance:
const WeeklyTrafficCardContainer = (props) => {
const [eachDateRange, setEachDateRange] = useState();
return (
<div>
{/* your return */}
<WeeklyTrafficCard setEachDateRange={setEachDateRange} />
</div>
)
}
If you need to display eachDateRange in the traffic card, or the traffic card needs to completely own that variable, you can create another state variable in the parent and pass a callback to the child (essentially what is above but now you have two different state variables).
The parent becomes
const WeeklyTrafficCardContainer = (props) => {
const [requestDateRange, setRequestDateRange] = useState();
const updateRequestDateRange = (dateRange) => {
setRequestDateRange(dateRange)
}
return (
<div>
{/* your return */}
<WeeklyTrafficCard updateDateRange={updateRequestDateRange} />
</div>
)
}
Then in your WeeklyTrafficCard call props.updateDateRange and pass it the date range whenever each_daterange changes.
Ciao, of course you need a global state manager. My preferred is react-redux. In few word, react-redux allows you to have a state that is shared in all your components. Sharing each_daterange between WeeklyTrafficCardContainer and WeeklyTrafficCard will be very easy if you decide to use it.
This is the more appropriate guide to quick start with react-redux. have a nice coding :)
Keep the value outside of the component, where both can access it. There are other ways to do this, but just as a simple example you could create a simple "store" to hold it and reference that store from each component that needs it:
class Store {
setDateRange (newDateRange) {
this._dateRange = newDateRange;
}
get dateRange () {
return this._dateRange;
}
}
export default new Store(); // singleton; everyone gets the same instance
import store from './Store';
const WeeklyTrafficCard = (props) => {
// use current dateRange value
const dateRange = store.dateRange;
// set new dateRange
store.setDateRange( newDateRange );
// do other stuff
}
import store from './Store';
const WeeklyTrafficCardContainer = (props) => {
// use current dateRange value
const dateRange = store.dateRange;
// set new dateRange
store.setDateRange( newDateRange );
// do other stuff
}
If you want store updates to trigger component re-renders you'd need to add some higher order component plumbing, like redux's connect, or some other mechanism for triggering updates:
// pseudocode; make store an event emitter and return
// a component that re-renders on store events
store.connect = Component => {
return props => {
React.useEffect(() => {
store.addEventListener( ... )
return () => store.removeEventListener( ... )
})
}
}
Or if the components share a common parent, you could lift the state to the parent and pass the information to each component as props. If either component updates the value, the parent state change will trigger a re-render of both components with the new value:
const Parent = () => {
const [dateRange, setDateRange] = React.useState();
return (
<>
<WeeklyTrafficCardContainer
dateRange={dateRange}
onDateRangeChange={newRange => setDateRange(newRange)}
/>
<WeeklyTrafficCard
dateRange={dateRange}
onDateRangeChange={newRange => setDateRange(newRange)}
/>
</>
);
}
Let's rephrase the objective here.
Objective: access each_daterange from WeeklyTrafficCard component in WeeklyTrafficCardContainer component.
Note: simply put, choose the following case based on your problem.
choose using prop if the variable is to be accessed by only one component
choose using context if the variable is to be accessed by more than one components
Solution Cases:
Case A: using prop.
Case A.1. WeeklyTrafficCard is the parent of WeeklyTrafficCardContainer
each_datarange being passed from WeeklyTrafficCard component as prop to WeeklyTrafficCardContainer component
working example for reference: codesandbox - variable passed as prop
// WeeklyTrafficCard.jsx file
const WeeklyTrafficCard = () => {
const [each_daterange, setDateRange] = useState();
return (
<>
...
<WeeklyTrafficCardContainer eachDateRange={each_daterange} />
</>
);
};
// WeeklyTrafficCardContainer.jsx file
const WeeklyTrafficCardContainer = props => {
const eachDateRange = props.eachDateRange;
return (
<>
...
</>
);
};
Case A.2. WeeklyTrafficCard & WeeklyTrafficCardContainer are children of a parent, say WeeklyTraffic component
each_datarange will be present in WeeklyTraffic component which is shared among WeeklyTrafficCard component & WeeklyTrafficCardContainer component
// WeeklyTraffic.jsx file
const WeeklyTraffic = () => {
const [each_daterange, setDateRange] = useState();
return (
<>
...
<WeeklyTrafficCard eachDateRange={each_daterange} />
<WeeklyTrafficCardContainer eachDateRange={each_daterange} />
</>
);
};
// WeeklyTrafficCard.jsx file
const WeeklyTrafficCard = props => {
const eachDateRange = props.eachDateRange;
return (
<>
...
</>
);
};
// WeeklyTrafficCardContainer.jsx file
const WeeklyTrafficCardContainer = props => {
const eachDateRange = props.eachDateRange;
return (
<>
...
</>
);
};
Case B: using context.
follow blog example found: blog - react context
this is preferred way to implement if the variable/variables is/are shared or need to be accessed by more than 1 components

Categories