Avoid double ajax call - ajax

I'm really new to React so I'm trying to manage it by made some examples. I made this component that made an ajax call to render a simple list.
import React from "react";
import axios from 'axios';
import Page from '../components/Page/Page';
import ListJobs from '../components/ListJobs/ListJobs';
let state ;
class Home extends React.Component{
constructor(props){
super(props);
this.state ={jobs:[]};
}
componentDidMount(){
var _this = this;
this.serverRequest = axios.get("http://codepen.io/jobs.json")
.then(function(result){
_this.setState({
jobs:result.data.jobs
});
});
}
componentWillUnmount() {
}
render(){
return(
<div>
<Page title="Home">
<p>Home</p>
<ul>
{this.state.jobs.map(function(job,index) {
return(
<ListJobs key={index} job={job}/>
);
})}
</ul>
</Page>
</div>
);
}
}
export default Home;
It calls another child component to render the li elements.
Everytime I call this component it starts with this ajax call, so I was wondering if there is a way to save the result of this ajax call and re-use it, instead of launching every time the request. I tried to do like this https://jsfiddle.net/corvallo/mkp4w8vp/
But I receive this error in the developer console:
Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of Home
Thank you in advance for your help

If you want the ajax calls only when the app launches, then you can make ajax calls on the parent component (probably App) and then pass it as a props to the Home component
EDIT
if you want to call the ajax only from the component, I think you can implement a cache or some sort e.g using localstorage
example
componentDidMount(){
let cache = JSON.parse(localStorage.getItem('homeCache') || "{}");
if(cache.hasOwnProperty('cached') && cache.hasOwnProperty('jobs')){
this.setState({jobs:cache.jobs});
}else{
(/*YOUR API HERE*/).then(function(result){
_this.setState({jobs:result.data.jobs});
localStorage.setItem('homeCache', JSON.stringify({cached: true, jobs: result.data.jobs}));
});
}
}
and everytime when the user exits the app, clear the cache (or anytime you want the cache to be cleared)
localStorage.setItem('homeCache', JSON.stringify({}));
I think that's one solution which popped out of my head right now..

Related

Differences between data in vue

I have tried to figure out why this happens but I have no idea why. I am going to post the code and then explain what happens. The issue is I do not know WHY this happens and it's annoying me like crazy!
Button:
<a
href="#"
v-for="(userStories, userStoriesIndex) in storiesData"
:key="userStoriesIndex"
#click="openUserStories(userStoriesIndex)"
>
Which loads:
<Stories v-for="(userStories, userStoriesIndex) in storiesData"
:key="userStoriesIndex"
>
<Story v-for="(story, storyIndex) in userStories.stories"
:key="storyIndex"
user-link="#"
:name="userStories.model.name"
:date="story.created_at"
close-button
#closeButtonClick="onCloseButtonClick"
>
<template #avatar>
<img :src="userStories.model.profile_photo_path" />
</template>
<img :src="story.media.preview_url" />
</Story>
</Stories>
And storiesData is loaded from this method:
getStories() {
axios
.get("/stories")
.then((response) => (this.storiesData = response.data));
}
which is loaded during mounted()
its loaded into:
data() {
return {
storiesData: [],
Now, when I click the button, the model loads incomplete, it is not loading the data... but... and this is where I lose it...
If I take the data from the Axios request, convert it to a JS object, and add it to the Vue file, everything works as intended.
I am not sure what's going on. I am completely at a loss why local would work and Axios would not. The data is IDENTICAL including but not limited to looking at Vue DevTools.
This sound to me like a bad async handling, Axios (and any other AJAX library), send the request asynchronously. It look like you thought that the rendering would wait for the ajax request to finish, but it is not. Try convert the axios call into Async/Await:
async function getStories() {
const data = await axios.get("/stories");
return data;
}
or for short:
async function getStories() {
return await axios.get("/stories");
}
then in your hydration function:
this.storiesData = await getStories();

Remix.run - common shared components

I’m just getting started learning remix.run and whilst I’ve gone through the tutorials there’s one bit I’m stuck on how I should implement it in remix.
If I wanted to display a common header that might toggle a sign in/sign out button based on the users logged in state where would this live?
My nextjs thinking would be to create the components and reference them in the common document. I know I can do this in the remix.server and remix.client files, but as my “login” component is and isn’t a route (I.e I might want to POST to the route when a user submits the login form but GET /login isn’t really a route) how would you structure something like this and would doing this even allow me to have loader and action functions in the shared component?
Do I just need to adjust my thinking about how to achieve this in remix or am I overthinking it and the above is perfectly valid?
I tried the following and it works. But then I end up just creating an empty "logout" route to process the form data with an action and loader that process the form in the case of the action or just redirect if a GET request via the loader. Is this the best approach?
export const SignIn = ({user}) => {
return (
<>
<form method="POST"action="/logout">
<input type="hidden" id="some" value="foo" />
{user ?
(
<button>sign out</button>
)
: (
<button>sign in</button>
)
}
</form>
</>
)
}
Thanks
based on https://remix.run/docs/en/v1/tutorials/jokes#build-the-login-form
it does indeed look like an empty route for logout:
import type { ActionFunction, LoaderFunction } from "#remix-run/node"
import { redirect } from "#remix-run/node"
import { logout } from "~/utils/session.server"
export const action: ActionFunction = async ({request}) => {
return logout(request);
};
export const loader: LoaderFunction = async () => {
return redirect("/");
};

React Router Switch Redux Dispatch

I have the below switch statement that routes the user to correct component based on the link they are on.
const Router = (props) => {
switch(props.page) {
case 'Equities' :
this.props.pageName('Equities');
this.props.pageURL('/Equities');
return <Equities />;
case 'Daily' :
return <Daily />;
default :
return ( <Redirect to="/Equities" /> )
}
}
const content = ({ match }) => {
return (
<div className="content">
<Router page={match.params.type} />
</div>
);
}
const mapDispatchToProps = {
pageURL,
pageName
};
export default connect(mapDispatchToProps)(content);
On the 4th line above, I am trying to dispatch an action to Redux to update page name and URL in the redux store that the user is on. I get the below error:
How can I dispatch actions based on the page user is on so I update name and URL to whichever page user is visiting?
So, for anyone experiencing this problem, it seems to be caused by my error on adding redux to the page crashing with the compose module.
My component structure for the app is like this:
App -> Skeleton -> TopBar, Sidebar, Content
So inside Content component I have a switch that displays the correct content for user. I was trying to add this functionality to Content. Now I added to Skeleton, and it works fine and is much better because I don't need to add now 8 different statements inside switch saying if match this do this do that. Now all I have is this.props.pageName(match.url); this.props.pageURL(match.params.type); so I record in redux the user is on and that's all.

How to use the pageContext in SPFx?

I am trying to get a value from the current page by using the pageContext but I am getting either undefined or 404.
This is the situation:
In the Site pages library there are several news pages. Each news page has some tags attached to them. This tags lives in a custom column in the Site Pages library.
There are news that have 1 tag and other several tags. It can be the situation where two or more news share the same tag(s).
The goal is when I open a news page the tags that are attached to that news are also visible.
Until now I am using #pnp/pnpjs and the code looks like this:
var result: any = await sp.web.lists.getByTitle("Site Pages")
.items.getById(15)
.select("Tags")
.get();
return await result.Tags;
And it is giving me 404 error
I also tried this one:
this.context.pageContext.list('Site Pages').listItem['Tags'].get().then((items: any[]) => {
console.log(items);
});
But it giving me Cannot read property 'list' of undefined
Du you have an idea how can get the value of the Tags column asociated with the current news?
Here is an update
Now I am getting the right tag. The question now is how to show it in the screen?
import * as React from 'react';
import styles from './ReadTags.module.scss';
import { IReadTagsProps } from './IReadTagsProps';
import { sp } from '#pnp/pnpjs';
export default class ReadTags extends React.Component<IReadTagsProps, {}> {
constructor(props: IReadTagsProps) {
super(props);
}
private async getTags() {
var id = this.props.context.pageContext.listItem.id;
var result: any = await sp.web.lists.getByTitle("Site Pages")
.items.getById(id)
.select("Tags")
.get();
return await result.Tags;
}
public render(): React.ReactElement<IReadTagsProps> {
console.log(this.getTags());
return (
<div className={ styles.readTags }>
<div className={ styles.container }>
<div className={ styles.row }>
<div className={ styles.column }>
</div>
</div>
</div>
</div>
);
}
}
Regards
Amerco
What you'll probably want to do is store your tags in the state of your component. Then you can show these (if the value from state is not empty) during your render. I can highly recommend working through the React tutorial to understand React lifecycle and state/props.
https://reactjs.org/tutorial/tutorial.html
https://reactjs.org/docs/state-and-lifecycle.html
Something with getting your data in componentDidMount, storing it in the state by using this.setState and then running through them in render with this.state.tags. It's more of a React question then a SPFx question :)
There's a ton of samples here with SPFx and React:
https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples

use parse react query results as an html tag attribute

This is my first time asking a question so I am a true SO newbie. I am currently working on a mobile app and I am using Parse React and Ratchet to build it. I have read the React documentations on FB github and apparently do not understand all enough to solve some problems. One of my problems is using the results of a Parse Query in the observe function of the declared ParseComponent as a value of a rendered react component, which in turn attempts to render the passed value as HTML. Below is the parent object:
export default class CategoryPage extends ParseComponent
{
observe(props,state){
return{
category: new Parse.Query('BusinessCategory').equalTo("objectId", this.props.categoryId)
};
}
render() {
return (
<div>
<Header text={this.data.category.objectId} back="true"/>
<div className="content">
<BusinessList categoryId={this.data.category.objectId}/>
</div>
<NavBar />
</div>
);
}
};
Notice I am passing the objectId of the category found in the Query as a text attribute of the Header React component. I am expecting Header as a child to use the passed property as follows:
var Header = React.createClass({
render: function () {
return(
<header className="bar bar-nav">
<h1 className="title">{this.props.text}</h1>
</header>
);
}
});
However the h1 is not rendering anything! I am thinking that this.data.category.objectId is a string and therefore should be rendered in the h1 tag as a string.
I do appreciate your answers very much.

Resources