How to access a useState globally? - reactjs

I am developing a ecommerce site and I have a feature to show cart Items number in nav bar. This nav bar is common for all page so it is in a different file. In the navbar I made the carticon into a react hook and used usestate to get and show cart number.
const CartNumber = () =>{
const [cartNumber, setCartNumber] = React.useState(0);
async function getCartN(){
var d = await getCartItem();
setCartNumber(d.cartData.length);
}
useEffect(()=>{
getCartN();
}, cartNumber);
return <NavLink to="/cart">
<MdOutlineShoppingCart className="cart-icon cart-icons" />
<span id="cart-count">{cartNumber}</span>
</NavLink>
}
Here if I use setCartNumber then the cart number would also update. But the problem is I want to call this outside this file since add to cart button is on another page. So how can I make this setCartNumber globally accesible.

You sould use a context api: https://reactjs.org/docs/context.html
Or a library like redux, to be able to manage the global state of your app: https://redux.js.org/

To achieve this goal, you have to use Redux or Context API.
By using one of them, you can use states globally and update them easily.

In React two states one is local and the second is global.
In Redux state management library handle both states. I highly recommended you should learn the Functional Programming concept and the second thing you learn is redux.
I already face this problem so Mosh instructor resolves my problem and clear the whole concept of redux.
I highly recommend you should see the Mosh redux series.
Context API is not preferred especially in big projects.

Related

How to perform a server side data fetching with React Hooks

We just start moving into React Hooks from the React life-cycle and one of the things that we noticed, is that there's no straightforward way to run something similar to ComponentWillMount for loading data before sending the rendered page to the user (since useEffect is not running on SSR).
Is there any easy way supported by React to do so?
I had the same problem. I've managed to solve it with a custom hook and by rendering application twice on the server-side. The whole process looks like this:
during the first render, collect all effects to the global context,
after first render wait for all effects to resolve,
render the application for the second time with all data.
I wrote an article with examples describing this approach.
This is a direct link to the example form article on CodeSandbox.
Also, I have published an NPM package that simplifies this process - useSSE on GitHub.
This is a little tricky but one way around is to do the fetch directly in the component as in
function LifeCycle(props){
console.log("perform the fetch here as in componentwillmount")
const [number, setNumber] = useState(0)
useEffect(() => {
console.log("componentDidMount");
return () => {
console.log("componentDidUnmount");
};
}, []);
}

Sharing data (an array) between two screens in tabs view using react-navigation in react native

I am using react-navigation without redux. so i have two tabs each with their own stack navigator, having one screen each. so i need and array of locations in both screens. currently i am doing this in both screens:
state = { locations: [] };
componentDidMount() {
this.getAllLocations();
}
async getAllLocations() {
let locations = await this.getMoviesFromApi();
this.setState({ locations });
}
i just want to have this array at one location and both components should share this single source of truth. so changes made by either screen is reflected in the other screen. Is this possible without redux?
RN 0.59 has opened great possibilities with its release. One of them are react hooks, which is available in the latest version... in the future react hooks will be used everywhere. Trust me. So, a while back I looked for the possibilities of having a global state using react hooks and found the reactn library. It uses react native hooks, and even you can use global state in CLASS components. which opens a new door for theming and sharing data. Now my app supports light/dark mode, dynamic font size, Languages, and early implementation of "portals" using only this library.
The best part about it is that you can use it like state. There is no need of provider, or redux stuff (although it provides it). It can be integrated with react navigation (it requires modifying some source code, at most, adding an "n" to react, and reference the global variable). Is awesome and I love it.
I have been thinking in doing an article on medium about this, because the lib is not that popular in RN community, but hope that you will give it a chance the library is only 22KB, less than one full component.
As an alternative, you could think about writing your own library using hooks. But it's gonna be hard. Try it, there is no going back
It is possible if you have a singleton object :
export default class SharedData {
constructor(){
if(SharedData.instance){
return SharedData.instance;
}
this.state = {locations:[]};
this.listners =[];
SharedData.instance = this;
return SharedData.instance;
}
setLocations(locations){
this.state.locations = locations;
this.listners.forEach(listner=>listner(this.state.locations));
}
getLocations(){
return this.state.locations;
}
addListner(listner){
this.listners.push(listner);
return listner;
}
removeListner(listner){
let index = this.listners.indexOf(listner);
if(index > -1){
this.listners.splice(index,1);
}
}
}
and then in every tab where you want to access shared locations state:
// get an instance of SharedData
this.sharedData = new SharedData();
// subscribe to locations changes
this.listner = sharedData.addListner((locations)=>{
this.setState({locations});
});
// set locations
this.sharedData.setLocations([]);
// unregister when destroying the component
this.sharedData.removeListner(this.listner);
I guess in order to achieve your goal, you're going to need some sort of a mechanism for storing 'global data', and if you don like Redux because it requires a lot of setup to achieve this simple task of sharing global data, then you chould you unstated ... which is alot simple to setup

Does React have keep-alive like Vue js?

I made a Todo list with React js. This web has List and Detail pages.
There is a list and 1 list has 10 items. When user scroll bottom, next page data will be loaded.
user click 40th item -> watch detail page (react-router) -> click back button
The main page scroll top of the page and get 1st page data again.
How to restore scroll position and datas without Ajax call?
When I used Vue js, i’ve used 'keep-alive' element.
Help me. Thank you :)
If you are working with react-router
Component can not be cached while going forward or back which lead to losing data and interaction while using Route
Component would be unmounted when Route was unmatched
After reading source code of Route we found that using children prop as a function could help to control rendering behavior.
Hiding instead of Removing would fix this issue.
I am already fixed it with my tools react-router-cache-route
Usage
Replace <Route> with <CacheRoute>
Replace <Switch> with <CacheSwitch>
If you want real <KeepAlive /> for React
I have my implementation react-activation
Online Demo
Usage
import KeepAlive, { AliveScope } from 'react-activation'
function App() {
const [show, setShow] = useState(true)
return (
<AliveScope>
<button onClick={() => setShow(show => !show)}>Toggle</button>
{show && (
<KeepAlive>
<Test />
</KeepAlive>
)}
</AliveScope>
)
}
The implementation principle is easy to say.
Because React will unload components that are in the intrinsic component hierarchy, we need to extract the components in <KeepAlive>, that is, their children props, and render them into a component that will not be unloaded.
Until now the awnser is no unfortunately. But there's a issue about it in React repository: https://github.com/facebook/react/issues/12039
keep-alive is really nice. Generally, if you want to preserve state, you look at using a Flux (Redux lib) design pattern to store your data in a global store. You can even add this to a single component use case and not use it anywhere else if you wish.
If you need to keep the component around you can look at hoisting the component up and adding a "display: none" style to the component there. This will preserve the Node and thus the component state along with it.
Worth noting also is the "key" field helps the React engine figure out what tree should be unmounted and what should be kept. If you have the same component and want to preserve its state across multiple usages, maintain the key value. Conversely, if you want to ensure an unmount, just change the key value.
While searching for the same, I found this library, which is said to be doing the same. Have not used though - https://www.npmjs.com/package/react-keep-alive

How to call method on a JSX element when writing functional react

I have recently started using React and Redux. One thing that often messes with my brain is how to re-write all the code examples from documentations that are usually written object based to my functional code base.
I am now in one of those situations; I can not find a way to call a method belonging to react-custom-scrollbars (link to docs) which I am using in one of my components. Below is a simplified version of the component. I have commented out the section where I would like to call the method scrollToBottom().
Bonus question: If I skip using the onUpdate() event, how would I go proceed if I want to call scrollToBottom() when a message is appended to the messages array?
const Chat = ({messages, app, keyDown, pressSend, setMessage, toggleEnter}) => {
return (
<div id="orbit-chat-content">
<Scrollbars
onUpdate={() => {
//
// HERE I WANT TO SCROLL TO BOTTOM
//
// this.scrollToBottom()
//
}}
className="react-scrollbar">
<div id="orbit-chat-conversation">
{ messages.map(message => <Message {...message} />) }
</div>
</Scrollbars>
</div>
);
};
export default Chat;
Thank you very much for taking your time to look at this!
The answer to your question:
Stateless components don't have refs. Which you would normally use to access the scrollbars instance.
Your real problem:
...how to re-write all the
code examples from documentations that are usually written object
based to my functional code base.
You don't have to. Statefull components are not deprecated or so. They are the base. PureRender Components / Functional components, are just an addition to the stack to provide a way of writing small independent components, like a Button.
Of course you can write a whole app only with stateless components, but if you need internal state, access to instances, some internal logic, you can and should use Normal Components too.

Using react-router-redux can Link components be used to transition after loading a routes state

I have been using react-router-redux which allows for my location to be stored in state nicely, and allows me to use react-router for defining routes, and linking between routes.
One problem seems to be that when I need to navigate using a <Link /> component like so:
<Link to={`/movie/${m.id}`}>
<p>{m.name}</p>
</Link>
this will trigger the change of route, and on load of the new route, in this case the <Movie /> route, the state for the movie page is loaded.
This doesn't really work nicely for transition between pages, as the new page will be blank on navigation, or you can put in a loader but really it should not navigate to the new page until the api call for the new page has loaded. Similar to sites like pitchfork.com or theguardian.com
This implementation has been discussed in this question and the approach of just using a loader between page transitions is used in the real-world-example and reddit api example
My question is, if I want to load state for the new container/route in my site before navigating, do I need to follow the approach suggested by dax chen in this question?
To sum up the answer was to fire an action and using redux-thunk we can preload the state by calling the action for the new container/route, then on completion we navigate to the page using react-router-redux's push() action
store.dispatch(push('/foo'))
If this is the recommended approach for preloading a page before transition, then I will be changing my react-router-redux-example and my current site to use this approach.
An action to load the new route's data then navigate will look something like this:
function fetchInit(url, id, to) {
return dispatch => {
return dispatch(fetchMovie(url, id))
.then(function(home) {
return dispatch(push(to))
})
}
}
It will need some logic to identify the new container's action to call and also the new path to navigate to. It may call the static fetchData() method on the new page's container component.
So this will somewhat complicate the <Link /> component, I am just looking for some advice on if this is the correct way, or I may have missed a simpler more recommended approach.
<Link onClick={ () => dispatch(navigate(`/movie/${m.id}`, 'Movie')) } >
<p>{m.name}</p>
</Link>
I made an implementation that solves this, and it is possible to make any type of custom link component and have it act in any way you like, however it is probably not a good idea for it to wait for a long load event before changing to a route, as users want the route transition to be immediate. The better approach is to use a nice loader and mix it in to the design of your page well, similar to what is done on pitchfork.com and also to ensure data comes back from the API quickly using caching e.g. redis, memcached.
Here is the library I made showing a custom react-router-redux link component: https://github.com/StevenIseki/react-router-redux-link

Resources