I have React component RandomQouteMachine which is supposed to get response from the provided URL and display it on the page. I don't see response displayed. The debug 'Did component mount ?' message is missing too..
import React, { Component } from 'react';
import axios from 'axios';
lass RandomQouteMachine extends Component {
constructor(props) {
super(props);
this.state = {
data: ""
};
}
componenetDidMount() {
console.log('Did component mount ?');
axios.get('https://api.icndb.com/jokes/random')
.then((res) => {
this.setState({data:res.value.joke});
})
}
render() {
return (
<div>
Here it is:
{this.state.data}
</div>
);
}
}
export default RandomQouteMachine;
Am I using componenetDidMount() correctly ? I can see only 'Here it is:' displayed on page
check your spelling.
componenetDidMount !== componentDidMount
Related
There are 2 separate components that fetch data through api. The code below is for the first component and then there is another component that fetch other data of the same company through another api and the code of that one is exactly the same except the api link. How to fetch the data from the other api in this component so there is no need for 2 different components.
import React, { Component, Fragment } from 'react'
import axios from 'axios'
class CompanyProfile extends Component {
constructor(){
super();
this.state={
Company:[]
}
}
componentDidMount(){
axios.get('http://localhost:3000/link').then(response =>{
**/////////for example axios.get('http://localhost:3000/link2') added here.**
this.setState({Company:response.data});
});
}
render() {
const cp = this.state.Company;
const CompanyView = contact.map((cp,i)=>{
**/////then mapped here.**
return <div>
<p>{cp.name}</p>
<p>{cp.type}</p>
<p>...other data</p>
**//// and then displayed here <p>{cp.CompanyProducts.data}</p>**
</div>
});
return (
<div>
{CompanyView}
</div>
)
}
}
export default CompanyProfile
I am not sure about your question. We can use container and presentational components.
A container does data fetching and then renders its corresponding sub-component. That’s it.
Refactor the CompanyProfile component to a stateless presentational component. Pass the company data from the remote API server to it from the container component.
So that we can reuse the CompanyProfile component.
CompanyProfile.jsx:
import React, { Component } from 'react';
class CompanyProfile extends Component {
render() {
const { campany } = this.props;
const CompanyView = campany.map((cp, i) => {
return (
<div>
<p>{cp.name}</p>
<p>{cp.type}</p>
<p>...other data</p>
<p>{cp.CompanyProducts.data}</p>
</div>
);
});
return <div>{CompanyView}</div>;
}
}
export default CompanyProfile;
Parent1.tsx:
import React, { Component } from 'react';
import axios from 'axios';
import CompanyProfile from './CampanyProfile';
export default class Parent extends Component {
constructor(props) {
super(props);
this.state = {
company: [],
};
}
componentDidMount() {
axios.get('http://localhost:3000/link').then((response) => {
this.setState({ company: response.data });
});
}
render() {
return <CompanyProfile company={this.state.company} />;
}
}
Parent2.jsx:
import React, { Component } from 'react';
import axios from 'axios';
import CompanyProfile from './CampanyProfile';
export default class Parent2 extends Component {
constructor(props) {
super(props);
this.state = {
company: [],
};
}
componentDidMount() {
axios.get('http://localhost:3000/link2').then((response) => {
this.setState({ company: response.data });
});
}
render() {
return <CompanyProfile company={this.state.company} />;
}
}
Good day to all!
I have this situation: I use Apollo client to get data from a GraphQL API endpoint in the parent class component in React. I pass this data to the child class component. The first time everything works fine but after a page refresh the data in the child component becomes undefined and the app crashes.
Here is the representation of the situation:
The ParentComponent
import React, { Component } from 'react'
import { gql } from "apollo-boost";
import {graphql} from 'react-apollo';
import ChildComponent from './ChildComponent'
const getProducts = gql`
{
category {
products {
id
name
gallery
}
}
}
`
class ParentComponent extends Component {
constructor(props) {
super(props)
this.state = {
products: []
}
}
componentDidMount() {
setTimeout(() => {
this.setState({
products: [...this.props.data.category.products]
})
}, 1000)
}
render () {
let products = this.state.products;
return (
<div><ChildComponent theProducts = {products}/></div>
)
}
}
export default graphql(getProducts)(ParentComponent);
The ChildComponent
import React, { Component } from 'react'
class ChildComponent extends Component {
constructor(props) {
super(props)
this.state = {
products: this.props.theProducts
}
}
render () {
let item = this.state.products.find(each => each.id === id);
return (
<div>
<ul>
<li>{item.name}</li>
<li><img src= {item.gallery[0]} alt="product"></img></li>
</ul>
</div>
)
}
}
export default ChildComponent;
So, when the app starts everything seems to work fine. But if I refresh the page it throws an error and says that name is undefined, gallery is undefined. It is clear that the data is not coming through to the ChildComponent. Is there a way to make sure that the data comes in at any time?
Thank you in advance.
You use theProducts in the ChildComponent but you pass theProduct from ParentComponent . And state product also has the same error. Just update to theProducts and product
I am handling react component by using router parameter,and also I have set router paramater value in state using componentDidMount event life cycle.It works fine as per my requirement,but "componentDidMount" does not fire on second time when I pass second router paramater value.Please check my below code and advise how to do this.
import React, { Component } from 'react';
import ConfigItem from '../../Config';
import axios from 'axios';
class ZohoDashboard extends Component {
constructor(props) {
super(props);
this.state = {url: ''};
}
componentDidMount() {
console.log('mount');
axios.get(ConfigItem[0].APIPath+'Menus/'+this.props.match.params.id)
.then(res => {
console.log(res.data.data[0].URL);
this.setState({url:res.data.data[0].URL});
})
}
render() {
console.log('render');
return (
<div class="embed-responsive embed-responsive-21by9">
<iframe class="embed-responsive-item" src={this.state.url} allowfullscreen></iframe>
</div>
);
}
}
export default ZohoDashboard;
Router params in url are supposed to trigger a prop change and hence do not remount the component. Instead they trigger a re-render, you can make use of componentDidUpdate to trigger an API when route param changes
class ZohoDashboard extends Component {
constructor(props) {
super(props);
this.state = {url: ''};
}
componentDidMount() {
console.log('mount');
this.fetchData();
}
fetchData = () => {
axios.get(ConfigItem[0].APIPath+'Menus/'+this.props.match.params.id)
.then(res => {
console.log(res.data.data[0].URL);
this.setState({url:res.data.data[0].URL});
})
}
componentDidUpdate(prevProps) {
if(prevProps.match.params.id !== this.props.match.params.id) {
this.fetchData()
}
}
render() {
console.log('render');
return (
<div class="embed-responsive embed-responsive-21by9">
<iframe class="embed-responsive-item" src={this.state.url} allowfullscreen></iframe>
</div>
);
}
}
I have a parent component called Home.js which retrieves the data from an API and send the data as a property to it's child component DishItem.js that shows the dish details. I am trying to render the dish_name, quantity (that can be changed) and net_cost, and I am storing all of these in a state and setting their state for the initial render through componentWillMount() lifecycle method. But it fails to set the state and returns undefined.
Home.js
import React, { Component } from 'react';
import DishItem from './DishItem';
import $ from 'jquery';
export default class Home extends Component {
constructor() {
super();
this.state = {
dish: ''
}
}
getDishes() {
$.ajax({
url: 'http://testbed2.riktamtech.com/foody_buddy/public/api/dishes/dish/31816',
dataType: 'json',
cache: false,
success: function(response) {
this.setState({dish: response.data});
}.bind(this),
error: function(xhr, status, err) {
console.log(err);
}
});
}
componentWillMount() {
this.getDishes();
}
componentDidMount() {
this.getDishes();
}
render() {
return (
<div className="Home">
<DishItem dish={this.state.dish}/>
</div>
);
}
}
DishItem.js
import React, { Component } from 'react';
import Quantity from './Quantity';
import { browserHistory } from 'react-router';
import './style.css';
export default class DishItem extends Component {
constructor(props) {
super(props);
this.state = {
quantity: 1,
delivery: '',
total_cost: '',
net_cost: null,
counter: 1
}
}
componentWillMount() {
console.log(this.props.dish.net_cost); //undefined instead of some value
this.setState({net_cost: this.props.dish.net_cost});
console.log(this.state.net_cost); // null
}
handleChangeInQuantity(value) {
var net_cost = 0;
var total_cost = 0;
total_cost = value * this.props.dish.cost;
net_cost = value * this.props.dish.net_cost;
this.setState({quantity: value, net_cost: net_cost, total_cost: total_cost});
}
saveAndContinue(e) {
e.preventDefault();
}
render() {
let address = <div>{this.props.dish.address}<br/>{this.props.dish.landmark}<br/>{this.props.dish.locality}</div>
return (
<div>
<h3>{this.props.dish.name}<small>{this.props.dish.description}</small></h3>
Total- {this.state.net_cost}
<Quantity change_in_quantity={this.handleChangeInQuantity.bind(this)} />
<button className="btn btn-default" onClick={this.saveAndContinue.bind(this)}>Next</button>
</div>
);
}
}
componentWillMount() function is triggered only once, it does not wait to get the data from the server. you should use componentWillReceiveProps() in the DishItem component, and set the new state with the data sent from the Home component to it. This way whenever the DishItem receives new props from the Home component, it will update accordingly.
You should not use the componentWillMount method of a React component to do asynchronous data fetching. Remove your call to the getDishes method and leave it in componentDidMount. In the render method of your Home component, check if the state already has the dish data in the state. If it doesn't, don't render the DishItem component. You can put a "Please wait, loading" message or something like that instead.
When the page is loaded, React will render the component with the "loading " message and start loading the dish data asynchronously. When the data is done loading and the state is set, React will render the component again with the DishItem component.
Here's an updated version of your Home component:
import React, { Component } from 'react';
import DishItem from './DishItem';
import $ from 'jquery';
export default class Home extends Component {
constructor() {
super();
this.state = {
dish: null
};
}
getDishes() {
$.ajax({
url: 'http://testbed2.riktamtech.com/foody_buddy/public/api/dishes/dish/31816',
dataType: 'json',
cache: false,
success: function (response) {
this.setState({ dish: response.data });
}.bind(this),
error(xhr, status, err) {
console.log(err);
}
});
}
componentDidMount() {
this.getDishes();
}
render() {
return (
<div className="Home">
{
this.state.dish === null ?
<div>Please wait, loading…</div> :
<DishItem dish={this.state.dish} />
}
</div>
);
}
}
it seems that I can't add a comment so I will just send this since there are already many answers. Please don't give me minus one because of this :)
Even though it is in componentDidMount, once it fetches the data, it will re-render the DOM so it will look like it is the initial render. If the fetching is slow, you will see it blank for a moment and then renders to what you need it to be.
If you really really need to make it show up at the very first moment, I suggest that you fetch the data and save it inside Flux store or Redux store before redirecting to this page. For example, fetch the data and do the redirection inside then() or callback function.
So I'm trying to mock an ajax call using a React's Container(purely to fetch the data and pass it along to its children), but I'm not getting anything.
Instead get the following error: TypeError: Cannot read property 'map' of undefined. Which basically tells me that the users is either empty or not yet defined, right?
Right now I'm following the following structure UserListContainer (fetches the data) => UserList Component (displays the data as a prop).
UserList Container
// Container responsible only to fetch User data
import React from 'react';
import UserList from '../../ui/components/users/userList.jsx';
export default class UserListContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
users: []
}
}
componentDidMount() {
$.ajax({
// url: "../../users/users.json",
url: "https://gist.githubusercontent.com/dantesolis/267a298f3d6ac524bc2a7d80960a16b5/raw/7929bb23f1757b85adcead4eed3023cd3c7453df/users.json",
dataType: "json",
success: function(users) {
this.setState({users: users});
}.bind(this)
});
}
render() {
// const usr = this.props.user;
// let usrs = users_mockup ? users_mockup : this.props.users;
return (
<UserList users={this.state.users} />
);
}
}
UserList Component
import React from 'react';
import User from '../users/user.jsx';
// import { Link } from 'react';
export default class UserList extends React.Component {
constructor(props) {
super(props);
}
renderUser({name, _id}) {
return <li>{_id}-{name}</li>
}
render() {
return (
<div className="main">
<ul>{this.props.users.map(renderUser)}</ul>
</div>
);
}
}
That is because users is undefined in the success callback. This can happen because the URL is not working correctly. After taking a look at it, it seems it returns javascript and not json. You should try removing the comment in the first line to make it json compliant.