React and Axios fires twice (once undefined, once successfully) - javascript

Following the React AJAX example i have created a JSX file which purpose is to fetch and render a movie.
For all i know, i am doing everything right here.
When i console.log the data in my render function i get 2 results:
Undefined
Object (which is the one i need, so this one is perfect)
How can i filter out the Undefined row without doing some if/else logic in my render function?
Iterating over the result will, of course, result in an error the first time, which will crash my application.
What's the best way to handle this?
EDIT: Maybe the app gets rendered before the Axios call is done in which case i am forced to do an if/else statement?
Heres my JSX file:
import React from "react";
import axios from "axios";
export default class NetflixHero extends React.Component {
constructor() {
super();
this.state = {
movie: []
}
}
}
componentDidMount() {
const apiKey = 'xxxxxxxx';
let requestUrl = 'https://api.themoviedb.org/3/' + this.props.apiAction + '&api_key=' + apiKey;
axios.get(requestUrl).then(response => {
this.setState({movie: response.data.results})
});
}
render() {
//Fires twice. Returns Undefined and an Object
console.log(this.state.movie[0]);
return(
<div></div>
)
}

Check the state inside the render method. With this approach you can render a loading screen:
import React from "react";
import axios from "axios";
export default class NetflixHero extends React.Component {
constructor() {
super();
this.state = {
movie: []
}
}
}
componentDidMount() {
const apiKey = '87dfa1c669eea853da609d4968d294be';
let requestUrl = 'https://api.themoviedb.org/3/' + this.props.apiAction + '&api_key=' + apiKey;
axios.get(requestUrl).then(response => {
this.setState({movie: response.data.results})
});
}
render() {
//Loading...
if( this.state.movie[0] === undefined ) {
return <div>Loading...</div>
}
//Loaded successfully...
return(
<div> Movie loaded... [Do action here] </div>
)
}
Explanation
Every time the state changes, a re-render will be triggered. The first time, your Component is constructed with this.state.movie = []. After that, componentDidMount() is triggered, which changes your state. This is triggering the render method a second time.

Is your post crossdomain?
If your request is a CORS (Cross-origin resource sharing) request it will be preceded with a OPTIONS (pre-flight) request. Have a look at CORS and more specifically to the pre-flighted requests.
Basically the OPTIONS request is used to check if you are allowed to perform the GET/POST request from that domain and what headers can be used for that request. This is not axios specific.

Related

How do I display on frontend the result of "methods.name.call()" web3 - method

I am developing a document verification system with ReactJS and solidity - smart contract. I want to display the result of my smart contract's get().call() method on the frontend, with a popup or even with a simple text.
My question is how can I do this? My .get().call() method seems to be working fine without any problem.
Check the image below, that's my code for now. I use console.log() to display the result.
If the console.log function displays your code in the console your codes work well, now you need to change the state by using this.setState function or useState hook to re-render the component. because in the ReactJS architecture, changing the state causes to change the interface. if your component is a class component:
import React, { Component } from 'react';
~~~
class YourComponentName extends Component {
constructor() {
super();
this.state = {
result: '',
~~~
~~~
};
}
onSubmitGet = async (event) => {
event.preventDefault();
cosnt hash = document.getElementById('hash').value;
await this.state.contract.methods
.get(hash)
.call({ form: this.state.address })
.then(res => this.setState({ result: res }))
};
~~~
render() {
const { result } = this.state;
return (
<>
<button onClick={this.onSubmitGet}>GET</button>
<div>{result}</div>
</>
);
}
};
The `~~~` means some other codes. actually, with using `setState` the `<div>{result}</div>` will change and show your result.

How can I evaluate text response as code in Javascript/React

I am using react to fetch a response from a server. I'm essentially scraping data from a chart to make a better chart. Anyway, the response comes back as javascript variables
'var x = [["data","like"this"],["and","like","this"]]'
When I use a plain .js file I can eval the response and then return x and it works.
However that same code when running inside of a React Class doesn't work.
Anyone know why or if somehow that variable is attaching to a different scope? I'm under the impression react doesn't run in strict mode so I think eval should work as far as setting variables.
import React from "react";
import ReactDom from "react-dom";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
this.getData();
}
getData() {
fetch("url-to-scrape")
.then(function(response) {
return response.text();//only way I can view the response
})
.then(data => {
eval(data) //should set variable x
console.log(x)// this is where I will setState
});
}
render() {
return (
<div>
<p>Smarter Chart</p>
</div>
);
}
}
ReactDom.render(<App />, document.getElementById("app"));
I have no clue why my response is coming back as Javascript variables. Either way, I figured out the way to parse this data in React.
import React from "react";
import ReactDom from "react-dom";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
componentDidMount() {
fetch("url-to-scrape")
.then(response => { //ReadableStream hiding response
return response.text(); //Convert ReadableStream to text
})
.then(data => {
var data_from_x = eval(data + "; x;"); //eval x and return it
this.setState({data: data_from_x });
})
}
render() {
return (
<div>
<p>welcome to the app</p>
</div>
);
}
}
ReactDom.render(<App />, document.getElementById("app"));
I eval the response text which is a string 'var x = data' In the eval I then add + '; x;' which calls that variables data within the eval. I set that data to a variable and then return it or in my case, setState. I now have a good amount of data for a fully customized chart.
I situations where I get multiple variables I can just pull all of them out the same way by name.
Since you expect to use x, there seems to be a guaranteed structure to the data. Assuming this to be a single variable declaration, you can extract this into json by grabbing a substring immediately after the equal sign. While this code needs to be changed if there is more than one variable in the response it is both safe to use and void of scope issues in contrast to eval.
const response = 'var x = [["data","like", "this"],["and","like","this"]]'
const output = JSON.parse(response.substring(response.indexOf('=') + 1))
console.log(output)

Need to Execute Function before render() in ReactJS

I've created a login system with React which stores a session when the user logs in. When the page is reloaded, I have added a function which should check if the session exists and then either setState() to true or to false.
As I'm new to React, I'm not sure how to execute this function. Please see my code below for App.js:
import React from 'react';
import './css/App.css';
import LoginForm from "./LoginForm";
import Dashboard from "./Dashboard";
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
renderLoginForm: true
};
this.handleLoginFormMount = this.handleLoginFormMount.bind(this);
}
handleLoginFormMount() {
this.setState({
renderLoginForm: false
});
}
// Check session function.
checkSession() {
fetch('/check-session', {
credentials: 'include'
})
.then((response) => {
return response.json();
})
.then((sessionResult) => {
if (sessionResult.username) {
console.log('false');
this.setState({
renderLoginForm: false
});
} else {
console.log('true');
this.setState({
renderLoginForm: true
});
}
})
.catch((error) => {
console.log('Error: ', error);
});
}
render() {
checkSession();
return (
<div className="App">
{this.state.renderLoginForm ? <LoginForm mountLoginForm={this.handleLoginFormMount} /> : null}
{this.state.renderLoginForm ? null : <Dashboard />}
</div>
);
}
}
export default App;
Having checkSession() in this position outputs the following in the console when loading the page:
Line 50: 'checkSession' is not defined no-undef
If I put the function outside of the class App extends React.Component {}, then it tells me that I cannot set the state of undefined.
Functional Component: In my case I wanted my code to run before component renders on the screen. useLayoutEffect is a hook provided by React for this exact purpose.
import React, { useLayoutEffect } from "react";
...
const App = () => {
useLayoutEffect(() => {
//check local token or something
}, []);
}
Read More: https://reactjs.org/docs/hooks-reference.html#uselayouteffect
Having checkSession() in this position outputs the following in the console when loading the page:
Line 50: 'checkSession' is not defined no-undef
That's because it's a method, but you're calling it like a freestanding function. The call should be this.checkSession();. But keep reading.
Separately:
The render function must be pure, it cannot have side-effects like changing state. Instead, put any side-effects code in componentDidMount; from the documentation for that lifecycle method:
If you need to load data from a remote endpoint, this is a good place to instantiate the network request.
Be sure that your component renders correctly for the original state (before the session check), as well as for the updated state (after the session check).
More about lifecycle methods and such in the documentation.
Alternately, if this component can't do anything useful without the session, you might move the session check to its parent component, and have the parent only render this child component when it has the session check results.

Put request get ID | Axios, React, Redux

I want to make a PUT request to my server, but in order to do so I need an identifier for the specific object I need to update. And that is my problem, I don't know how to get the components id so I can fulfill my PUT request. Here's the code at the moment:
import axios from 'axios'
import settings from '../../../../settings'
axios.defaults.baseURL = settings.hostname
export const updateSettings = function(id, item) {
return dispatch => {
axios
.put(`${settings.hostname}/locks/${id}`, item)
.then(res => res.data)
.catch(err => console.log(err))
}
}
When console.log item I can see all the new thing I've typed in my input fields (the things I want to change), but I'm getting this also:
And sometimes 404. So my question is how can I get the id so I can make this put request. Thank you.
This is where I call updateSettings:
import React, { Component } from 'react'
import { updateSettings } from './redux/actions/updateSettingsAction'
import DoorSettingsForm from './components/doorsSettingsForm'
import { connect } from 'react-redux'
class DoorSettingsContainer extends Component {
submit(values) {
this.props.updateSettings(values)
}
render() {
return (
<div>
<DoorSettingsForm
onSubmit={this.submit.bind(this)}
item={this.props.location.state.item}
/>
</div>
)
}
}
function mapStateToProps(state) {
return { data: state.data }
}
export default connect(mapStateToProps, { updateSettings })(
DoorSettingsContainer
)
You've missed the id on the updateSettings() function
look at this line: export const updateSettings = function(id, item) {};
and then the line where you call it:
submit(values) {
this.props.updateSettings(values)
}
your item is your id here, and the item is nowhere to be found, i think this is where you get most of your problems atleast for now from.
What you are currently doing is passing the event object received by the onSubmit handler to the updateSettings method.
Mind that in your event handler you have access to both state and props:
submit() {
// this comes from the redux binding
const { data } = this.props
// this is local state, not sure what else of interest is in there
const item = this.state.location.item
// Just a guess, inspect your data to see what's appropriate here.
this.props.updateSettings(data.id, item)
}
Inspect your data, you probably need to access data.id or item.id to get the proper id updateSettings needs.
Also pay attention that if you are dispatching async actions this way, then depending on what middleware you are using, you will probably have to call dispatch when the async data comes in (e.g. where you can access res.data).

Next.js React component getInitialProps doesn't bind props

In Next.js, you can use in your React components a lifecycle method bound to the server side rendering on first load.
I tried to use this function as presented in the ZEIT tutorial (alternatively on their Github), but this.props doesn't seem to get JSON returned by the function.
When I click on the component, console print an empty object.
import React from 'react'
import 'isomorphic-fetch'
export default class extends React.Component {
static async getInitialProps () {
const res = await fetch('https://en.wikipedia.org/w/api.php?action=query&titles=Main%20Page&prop=revisions&rvprop=content&format=json')
const data = await res.json()
return { data }
}
print() {
console.log(this.props);
}
render() {
return <div onClick={this.print.bind(this)}>print props</div>
}
}
I had this issue due to a problem in my _app.js (i.e. NextJS Custom App) which I caused while adding in Redux (not a Redux issue). As soon as I started using getInitialProps in a page my props were empty at render though data was there in the static call. The cause was the incorrect propagation of pageProps in my _app.js.
So in my case the fix was changing, in custom _app.js getInitialProps, this:
return {
...pageProps,
initialReduxState: reduxStore.getState()
}
to:
return {
pageProps: {...pageProps},
initialReduxState: reduxStore.getState()
}
.. so the render method as seen in the NextJS doc link could wire them through.
you can make your call in getInitialProps method like this with little modification in your code
import React from 'react'
import 'isomorphic-fetch'
export default class extends React.Component {
static async getInitialProps () {
const res = await fetch('https://en.wikipedia.org/w/api.php?action=query&titles=Main%20Page&prop=revisions&rvprop=content&format=json')
const data = await res.json()
return { jsonData: data }
}
print() {
console.log(this.props.jsonData);
}
render() {
return <div onClick={()=> this.print()}>print props</div>
}
}
I tried your code and it seems to work fine, console shows this.props:

Categories

Resources