I'm doing a basic React app with data coming from my api. But the state is not updated when I do this.setState({}) after AJAX success. The state.events is empty in the render method.
What am I doing wrong?
import React, {PropTypes, Component} from 'react';
import axios from 'axios';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
events: []
};
}
componentDidMount() {
axios.get('http://localhost:4000/api/v1/events')
.then(function (response) {
this.setState({events: response.data});
})
.catch(function (error) {
console.warn(error);
});
}
render() {
// this.state.events keeps being an empty array []
return (
<div className="home">
{
this.state.events.map((month) => {
console.log(month)
})
}
</div>
);
}
}
export default App;
The way you are using should throw the error, check the console. You need to bind the context to use this keyword inside callback method that you are using in .then, Use this:
componentDidMount() {
axios.get('http://localhost:4000/api/v1/events')
.then( response => {
console.log('data', response.data);
this.setState({events: response.data});
})
.catch(function (error) {
console.warn(error);
});
}
or use .bind(this) to bind the context, like this:
componentDidMount() {
axios.get('http://localhost:4000/api/v1/events')
.then(function (response) {
this.setState({events: response.data});
}.bind(this))
.catch(function (error) {
console.warn(error);
});
}
You need to bind axios success function to the correct context to make use of setState. USe this
componentDidMount() {
axios.get('http://localhost:4000/api/v1/events')
.then(function (response) {
this.setState({events: response.data});
},bind(this))
.catch(function (error) {
console.warn(error);
});
}
this
inside callback doesn't refer to your component context for that you need to bind your callback function of axios with your react component to update state of that component
import React, {PropTypes, Component} from 'react';
import axios from 'axios';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
events: []
};
}
componentDidMount() {
axios.get('http://localhost:4000/api/v1/events')
.then(function (response) {
this.setState({events: response.data});
}.bind(this)) // binding of callback to component
.catch(function (error) {
console.warn(error);
});
}
render() {
// this.state.events keeps being an empty array []
return (
<div className="home">
{
this.state.events.map((month) => {
console.log(month)
})
}
</div>
);
}
}
Related
I have a Vue.js component in Laravel, it's loading with:
Vue.component('user-profile', require('./components/UserProfile.vue').default);
However, when I use this.$router.go() in it, I get the following error:
TypeError: Cannot read property '$router' of undefined
So, I've add this to my routes:
const routes = [
{
path: '/profile',
component: UserProfile
},
...
];
But then, I get:
Uncaught ReferenceError: UserProfile is not defined
So, I replaced:
Vue.component('user-profile', require('./components/UserProfile.vue').default);
by:
import UserProfile from './components/UserProfile.vue';
But I get this error:
Unknown custom element: - did you register the
component correctly?
How should I fix this issue to be able to use this.$router.go() in my component ?
=== EDIT ===
I'm using this.$router.go() here:
methods: {
async update () {
await axios.put(`/api/user/` + this.data.id, this.user)
.then(function (response) {
console.log(response);
this.$router.go()
})
.catch(function (error) {
console.log(error);
});
}
},
Either Use arrow function
methods: {
async update () {
await axios.put(`/api/user/` + this.data.id, this.user)
.then((response) => { // check here
console.log(response);
this.$router.go()
})
.catch((error) => {
console.log(error);
});
}
},
Or use var vm = this;
methods: {
async update () {
var vm = this;// check here
await axios.put(`/api/user/` + this.data.id, this.user)
.then(function (response) {
console.log(response);
vm.$router.go(); // check here
})
.catch(function (error) {
console.log(error);
});
}
},
Read about arrow function
I am learning React and I am trying to display a list of users from and ajax call. I am getting an unexpected token error from CodePen when I add the line
export default Users;
When I remove the line there are no more errors but the list of users is not being displayed.
My code:
function GetUsers(project){
$.ajax({
url: "https://jsonplaceholder.typicode.com/users",
success: function (data) {
console.log(data);
callback(null, data);
},
error: function (error) {
console.log(data);
callback(error, {});
}
});
}
function UserList(users) {
const userItems = users.map((user) =>
<ul>
<li>
{ user.name }
</li>
<li>
{ user.email }
</li>
<li>
{ user.phone}
</li>
</ul>
);
return (userItems);
}
class Users extends Component {
componentDidMount() {
GetUsers(null, function (err, data) {
if (err)
{
console.log(err);
}// do something
this.setState({ users: data })
}.bind(this))
}
render() {
return(
<UserList user = {this.state.users} />
);
}
}
if (document.getElementById('root')) {
ReactDOM.render(<Users />, document.getElementById('root'));
}
Here is my code.
Thank you for any and all help!
Problem 1 in AJAX call
function GetUsers(project){
$.ajax({
url: "https://jsonplaceholder.typicode.com/users",
success: function (data) {
console.log(data);
callback(null, data);
},
error: function (error) {
console.log(data);
callback(error, {});
}
});
}
$.ajax is asynchronous call, that means it doesn't returns directly any value (how it could if it is fetching the results from the internet) it Just creates another function which will call success and error when completed.
That's why we need to wrap it with callbacks
function GetUsers(project, resolve = () => {}, reject = () => {}) {
}
Problem 2 in mount
componentDidMount() {
GetUsers(null, function (err, data) {
if (err)
{
console.log(err);
}// do something
this.setState({ users: data })
}.bind(this))
}
This code is completely wrong, it has even syntax error so not worth to discuss it in details.
We need to call our new function and pass success callback for mutating the state
GetUsers(null, users => {
this.setState({ users });
});
In this way we will call GetUsers wait for it's results and only after that we will mutate the state with new result
3 problem in component creation
React component's don't have state by default, you need to infer the state from constructor so we need to change initialization to
constructor(props) {
super(props);
this.state = {
users: false
};
}
otherwise you will get Cannot call setState of undefined as state is not automatically created for performance purposes and all components are Pure by default.
I have created a working sandbox here
in
function GetUsers(project){
$.ajax({
url: "https://jsonplaceholder.typicode.com/users",
success: function (data) {
return data;
},
error: function (error) {
console.log(error);
return {};
}
});
}
--
success: function (data) {
return data;
}
doesn't do what you think it does. return data isn't really returning the data... anywhere.
You need to have a callback.
function GetUsers(project, callback){
$.ajax({
url: "https://jsonplaceholder.typicode.com/users",
success: function (data) {
callback(null, data)
},
error: function (error) {
callback(error, {})
}
});
}
class Users extends Component {
componentDidMount() {
GetUsers(null, function (err, data) {
if (err) // do something
this.setState({ users: data })
}.bind(this))
}
render() {
return(
<UserList user = {this.state.users} />
);
}
}
you can also Promise-ify things to simplify the logic
I am trying to consume rest api in ReactJS. But it's showing undefined.
Here is my code..
ReactJS code:
<script type="text/jsx">
var JavaEEWSTest = React.createClass({
getInitialState: function () {
return {text: ''};
},
componentDidMount: function(){
$.ajax({
url: "http://localhost:8080/hi"
}).then(function(data) {
this.setState({text: data.text});
alert(data.text);
}.bind(this))
},
render: function() {
return <div>Response - {this.state.text}</div>;
}
});
React.render(<JavaEEWSTest />, document.getElementById('component'));
</script>
Here is my Spring boot code:
#RestController
#CrossOrigin(origins = "http://localhost:3000")
public class HelloController {
#RequestMapping(value="/hi",method=RequestMethod.GET)
public String sayHello()
{
return "hello";
}
}
While making AJAX calls, we can use axios-react, the quick link: https://www.npmjs.com/package/axios
And instead of the function keyword in your code, you may use the ES6 version's =>.
Below is an example of getting the response from the rest API.
constructor() {
super();
this.state = {
data : []
}
}
componentDidMount() {
axios.get(URL)
.then((res) => {
this.setState({data:res.data});
console.log(this.state.data);
})
.catch((error) => {
console.log(error);
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
I create SPA with VueJs and Laravel.
Homepage i get all posts via api laravel and axio responsive had data object.
But i can not update to posts property.
Error in chrome debug tool:
My code in Wellcome.vue
import { mapGetters } from 'vuex'
import axios from 'axios'
export default {
name: 'welcome',
layout: 'default',
metaInfo: { titleTemplate: 'Welcome | %s' },
computed: mapGetters({
authenticated: 'authCheck'
}),
data: () => ({
title: 'Demo Blog',
}),
props: {
posts: {
type: Object
}
},
created () {
axios.get('/api/posts')
.then(function (response) {
this.posts = response.data;
})
.catch(function (error) {
console.log(error);
});
},
}
You are using a regular function as a callback which means this reference changes. You need to use arrow function here . () => {}.
axios.get('/api/posts')
.then((response) => {
this.posts = response.data;
})
.catch((error) => {
console.log(error);
});
First of all you defined posts in your props property. You should not mutate a prop from child component. Props are One-Way-Data-Flow
you can inititialize posts in you data property as follows:
data(){
return{
posts: null
}
}
Then you can fetch data via your API and assign it to your posts in the data property
this in you then function does not point to the vue instance.
So its better you do it like this
created () {
var vm = this;
axios.get('/api/posts')
.then(function (response) {
vm.posts = response.data;
})
.catch(function (error) {
console.log(error);
});
},
}
Or you an => function like this
created () {
axios.get('/api/posts')
.then( (response) => {
this.posts = response.data;
})
.catch(function (error) {
console.log(error);
});
},
}
Im trying to write simple ajax loader and I wondering that i can prevent props.children render in parent container. The problem is that children want to render, no matter that Loader want to show it or not, and if render is based on ajax data that cousing errors.
Example: https://jsfiddle.net/j8dvsq39/
Example2:
This example will produce error couse this.state.data.user is undefined before ajax request.
Loader:
import React from 'react'
export default React.createClass({
getDefaultProps() {
return { text: "Loading", loaded: false };
},
render() {
if(this.props.loaded == false)
return <div>{this.props.text}</div>;
else
return <div>{this.props.children}</div>;
}
})
Class using Loader
import React from 'react'
import Loader from '../helpers/Loader';
import {comm} from '../Comm';
export default React.createClass({
getInitialState() {
return {loaded: false, data: null};
},
componentWillMount(){
comm.get("/xxx/xxx", {json: 1}, (back) => {
console.log(back);
this.setState({loaded: true, data: back});
});
},
render(){
return <Loader loaded={this.state.loaded}>{this.state.data.user.name}</Loader>
});
Reason is, initially you defined data=null and before the ajax call you are using this.state.data.user.name, it will throw the error:
Cannot read property 'name' of undefined
Simple solution is you need to put the check on data until you didn't get the ajax response, Check this:
var Loader = React.createClass({
getDefaultProps() {
return { text: "Loading", loaded: false };
},
render() {
if(this.props.loaded == false)
return <div>{this.props.text}</div>;
else
return <div>{this.props.children}</div>;
}
});
var Hello = React.createClass({
getInitialState() {
return {loaded: false, data: null};
},
componentWillMount(){
setTimeout(()=>{
this.setState({loaded: true, data: {user:{name: "login"}}});
}, 1000);
},
render: function() {
var user = null;
return <Loader loaded={this.state.loaded}>
<div>
Hello {this.state.data ? this.state.data.user.name : null}
</div>
</Loader>;
}
});
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='container'/>