How prevent calling same api in different components in react js - reactjs

I am working large reactjs application,In that application so many components are there and so many api services also there.
My problem is how to prevent calling same api in different components.
Actually i want to call api one time then ,i will use that api response entire application ,so that we can prevent calling same api in different components.
So please give me any solution.
check the below demo code:
enter code here
`FirstComponent:
——————————————
Class FirstComponent extends Component {
constructor(props){
this.setState={}
}
componentDidMount() {
this.props.dispatch(getById(1)); //here first time I am calling api
}
render(){
return(
———HTML Code HERE———
)
}
const mapStateToProps = state => {
  return {
    registrationData: state.RegistrationDemand.registrationData
// here I am getting response through redux reducer store
    };
};
export default compose(
  translate,
  withRouter,
  connect(mapStateToProps)
)(FirstComponent);
SecondComponent:
——————————————
Class SecondComponent extends Component {
constructor(props){
this.setState={}
}
componentDidMount() {
this.props.dispatch(getById(1)); //here I need to prevent this second time api calling
}
render(){
return(
———HTML Code HERE———
)
}
const mapStateToProps = state => {
  return {
    registrationData: state.RegistrationDemand.registrationData
//without calling second component,If I use this one first time when I redirect to this page data is coming hereabout when I refresh second time it is getting null.
    };
};
export default compose(
  translate,
  withRouter,
  connect(mapStateToProps)
)(SecondComponent);`

You can actually call the API once your application is mounted. Usually this is done via componentDidMount or if you're using hooks, you can add it inside useEffect.
And you can just pass down props.
A more better solution is to use redux to your project, wherein the whole state of your application is inside a store in which you can connect using react-redux.

Related

React API Boundary for Managing API Queries

Is there a way to wrap React components with a boundary similar to an ErrorBoundary, but instead track API query promises? I am finding that this may not be possible just because the inner components within the boundary will not be able to access their owner APIBoundary component without breaking some best practices.
My use case is: I have a page with a very large number of API queries which return promises. When that page unmounts, those queries continue to wait and the website lags until they're done. I can cancel those promises if I can store and retrieve the lowest level promise returned by my API function. But storing all of those promises buried within multiple layers of utilities and other components is not easy when I need to cancel them from componentWillUnmount in an owner component 3 layers up.
My API calls are to AWS AppSync, so they look like this:
const promise = API.graphql(graphqlOperation(query, variables));
An APIBoundary would look something like this with nested components multiple layers deep before API calls:
<APIBoundary>
<ComponentThatUnmounts>
<ComponentA>
<ComponentB>
<ComponentThatCallsAPI />
</ComponentB>
</ComponentA>
</ComponentThatUnmounts>
</APIBoundary>
The boundary would look like this:
class APIBoundary extends React.Component {
constructor(props) {
super(props);
this.promises = [];
this.enabled = true;
}
async cancelableQuery (query, variables) {
if (!this.enabled) {
return null;
}
const promise = API.graphql(graphqlOperation(query, variables));
this.promises.push(promise);
return await promise
}
componentWillUnmount() {
this.enabled = false;
if (this.promises?.length) {
this.promises.forEach((p) => {
try {
API.cancel(p, reason);
} catch {}
});
}
}
}
As I'm writing this, I'm thinking maybe the only solution is to make an APIComponent as a parent component to ComponentThatCallsAPI. The APIComponent would have parent functions that perform the operations I need and control the componentWillUnmount of the ComponentThatCallsAPI. I would rather not do this though because it requires inheriting from the APIComponent rather than another parent component that I may want to inherit from, and requires making sure I'm not stepping on other unmount operations. A Boundary would be a simple add-on to anywhere I need to worry about unmounting.

ReactJS - Triggering Re-render from external Process

Im very new at React and Frontend development. Its literally my first Project now and I have design problem listening to external events. So basically I want to build a UI that only changes on external Events, meaning you control it with another Process (e.g. an AI that triggers the changes). The App should listen to incoming messages and depending on the message it should update the UI.
My idea was to make the Component, that receives the messages from outside, an observable and notify the MainApp of the React-Ui. The following code should give an idea to my approach.
export default class App extends Component {
constructor(props){
super (props);
this.state = {mode: "idle"};
this.observable = new Observable();
this.observable.add((m) => mode(m));
}
mode(m){
this.setState({
mode: m
});
}
render() {
return (
<div>
<Home/>
<ComponentA mode={this.state.mode}/>
<ComponentB mode={this.state.mode}/>
</div>
)
}}
My Question now is, Is this a good way to update the UI or are there maybe better ways or pattern that I can use or that are common in Frontend-Development?
Your approach is totally valid, I don't see any issues with it.
You could try initializing the observable in a lifecycle method instead like componentDidMount. You could even use redux to manage the data passed from the observable.

Will ReactDOM.hydrate() trigger lifecycle methods on the client?

From the React 16 docs about ReactDOM.hydrate(),
Same as render(), but is used to hydrate a container whose HTML contents were rendered by ReactDOMServer. React will attempt to attach event listeners to the existing markup.
Will ReactDOM.hydrate() also trigger lifecycle methods on the client such as componentWillMount(), componentDidMount() during initial render?
Will render() method be called on the client during hydration? I suppose not, because that's the difference between ReactDOM.render() and ReactDOM.hydrate()?
If render method won't be called on the client, we wouldn't expect componentDidMount() lifecycle method to be triggered.
If none of the lifecycle methods are called on the client, how would we know when has React finished rendering. I suppose the callback in the following syntax:
ReactDOM.hydrate(element, container[, callback])
I want to understand if there are lifecycle methods / hooks (which give more control over the application) available when React is "attempting to attach event listeners to existing markup".
Since ReactDOM.hydrate is (and should be) called on the client then YES it is supposed to run componentDidMount. componentWillMount is already called when rendered on the server.
componentDidMount does not run on the server, therefore when you call hydrate, the app runs the event.
Think about hydrate as a different render method. It does render but not in the same way. It looks for mismatches between your server rendered React and your client React. It does not render everything again.
React expects that the rendered content is identical between the server and the client. It can patch up differences in text content (such as timestamps), but you should treat mismatches as bugs and fix them
However you might want to do some crazy stuff like rendering something completely different on the client side (than what was rendered on the server). For this pay attention to this paragraph
If you intentionally need to render something different on the server and the client, you can do a two-pass rendering. Components that render something different on the client can read a state variable like this.state.isClient, which you can set to true in componentDidMount(). This way the initial render pass will render the same content as the server, avoiding mismatches, but an additional pass will happen synchronously right after hydration. Note that this approach will make your components slower because they have to render twice, so use it with caution.
So as you can see it does a render pass. If there are no mismatches React is optimized for that.
I hope it was clarifying. I speak from experience with React SSR and basic understanding of reading the docs.
The rendered elements probably aren't same between server and client, because initially the elements are rendered into texts at the server in memory, therefore they are not mounted. When the content is moved to client, it can be re-attached to react via hydrate which is fake "render" to wire with the rest of react functionalities, such as events.
In order to tell when it's hydated, here's a piece from internet which I found clearly stated the above rational. https://dev.to/merri/understanding-react-ssr-spa-hydration-1hcf?signin=true
const HydrateContext = createContext('hydrated')
export function useIsHydrated() {
return useContext(HydrateContext)
}
export function IsHydratedProvider({ children }) {
const [isHydrated, setIsHydrated] = useState(false)
useEffect(() => {
setIsHydrated(true)
}, [])
return (
<HydrateContext.Provider value={isHydrated}>
{children}
</HydrateContext.Provider>
)
}
To use it,
function MyComponent() {
const isHydrated = useIsHydrated()
return !isHydrated ? 'Initial render' : 'SPA mode'
}
function App() {
return (
<IsHydratedProvider>
<MyComponent />
</IsHydratedProvider>
)
}
It feels to me, any rendered component teleports from the server to the client.
p.s Here's another article which talks about the second render after the mount, https://medium.com/swlh/how-to-use-useeffect-on-server-side-654932c51b13
I read the type of ReactDOM.hydrate in TypeScript system:
(
element: SFCElement<any> | Array<SFCElement<any>>,
container: Container| null,
callback?: () => void
): void;
And example to the above declaration:
ReactDOM.hydrate(
<App />, // element
document.getElementById('root'), // container
() => { // callback
/* do what you want after hydration */
}
);

Firebase and React with react-snapshot (pre-rendering)

I"m new to firebase, just wrote a little simple test react component before putting all of data on to firebase, but unfortunately I couldn't make it work with Server Side Pre-Rendering. It's very important to make it SEO friendly for me, and I've searching around on the internet for the solution, but still couldn't really figure it out. please help me out with this. thanks very much in advance.
The simple code below will only generate the initial state with React-Snapshot, when I open the the page it will show initial state and then update to newer state. But I need to make the initial state object fetching data directly from Firebase and generate static html with React-Snapshot.
class FirebaseTestingComponent extends Component {
constructor(){
super();
this.state = {
speed: 10
};
}
componentWillMount(){
const rootRef = firebase.database().ref().child('react');
const speedRef = rootRef.child('speed');
speedRef.on('value', snap => {
this.setState({
speed: snap.val()
});
});
}
render(){
return (
<div>
<h1>{this.state.speed}</h1>
</div>
);
}
}
By SEO friendly I assume you want static content instead of dynamic (not an expert on SEO) but firebase runs asynchronously especially when you use .on() that's like websocket, doesn't matter if you do willmount or didmount this case.
My humble suggestion for the design is to fetch from firebase in your server before render the page (firebase support java and node for sure, not sure about the rest), and set initial state with that value you fetched, that will guarantee your initial state is from firebase. From that you can still use that .on() for later value coming in.

React with REST API - State or GET on mount?

We're currently building a React-Redux frontend with a REST API backend powered by Node. I'm unsure about whether to use a Redux or a simple call to the API on mounting the component.
The component is a simple list of profiles which are going to be displayed throughout (but not constantly) the site.
Sorry for asking this. Maybe there's something to read through available?
I would advice you to take a look at two things:
1) The first React tutorial on Facebook is very underrated:
https://facebook.github.io/react/docs/thinking-in-react.html
It exposes a very clear way to think about how to think about the tree structure of your views.
2) From there, move to reading about Containers and Components:
https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
This post explains that React components too often do two things: act as renderers and as controllers (taking on both the V and the C on MVC).
Now, what your React view needs is a controller. Fetching it whenever you mount the component overlaps two different concerns: how to display the information and how to fetch it.
You could do it with a single, bigger React component that manages the complete state of your application:
class MyApp extends React.Component {
componentDidMount() {
fetch('/profiles').then(res => res.json().then(::this.setState))
}
render() {
if (this.state) {
return <ProfileList profiles={this.state} />
} else {
return <span>Loading...</span>
}
}
}
That would be your "Container". Your "Component" is a pure representation of the list of profiles, that needs not care about how that information was retrieved:
class ProfileList extends React.Component {
render() {
return <ul>
{
this.props.profiles.map(
profile => <li key={profile.id}>{profile.name}</li>
)
}
</ul>
}
}
Redux is just another way of doing this that enables better reuse of information, and makes that same information available to different components (hiding the instance of the "store" as a mixin). That MyApp class on top of your structure serves a similar function to the Provider class in redux: allowing child components to access information needed to display themselves.

Resources