I am practicing using axios in ReactJs where i have my App.js component which is in charge of fetching de data of my api using axios. This App.js renders a component that containt child components in it and one of the child component is my ImageList.js component where im rendering the list of images by mapping the array.
App.js:
import React, { Component } from 'react'
import SearchInput from './components/SearchInput'
import axios from 'axios';
import ImageList from './components/ImageList';
export default class App extends Component {
state = {images: []}
onSearchSubmit = async(entry) => {
const response = await axios.get(`https://pixabay.com/api/?key=29058457-42bf8a0bcd2bc1293e234b193&q=${entry}&image_type=photo`)
console.log(response.data.hits)
this.setState({images:response.data.hits});
}
render() {
return (
<div className='ui container' style={{marginTop:'30px'}}>
<SearchInput onSearchSubmit={this.onSearchSubmit}/>
We have {this.state.images.length} Images
<ImageList images={this.state.images}/>
</div>
)
}
}
ImageList.js:
import React from 'react'
const ImageList = (props) => {
const images = props.images.map((image) =>{
return <img key={props.id} src={image.webFormatURL} alt="image" />
});
return (
<div>{images}</div>
)
}
export default ImageList
The error is suposed to be at line 10:11 at ImageList.js
images is undefined
Related
i am working on small react assignment,
following is my component code. So my component is getting rendered once but then it just fails.i'll attach the screenshots too, can some one please explain what is happening?is there an error in the code or is it because of some rate limiting in API i am using?
import React from 'react'
const Menu = ({events}) => {
console.log(events);
return (
<div>
{events.map((event)=>{
return( <div key={event.category}>
<h3>{event.category}</h3>
</div>)
})}
</div>
)
}
export default Menu
code working image
error on same code pic
parent component code
import React,{useState,useEffect} from 'react';
import './App.css';
import Menu from './components/Menu';
function App() {
const [isLoading,setISLoading] = useState(true);
const[events,setEvents] = useState()
const getEvents = async()=>{
const response = await fetch('https://allevents.s3.amazonaws.com/tests/categories.json');
const eventsData =await response.json()
setISLoading(false);
setEvents(eventsData);
}
useEffect(()=>getEvents(),[]);
return (
isLoading?<h1>Loading...</h1>:<Menu events = {events}/>
);
}
export default App;
May be the parent component of Menu which is supplying events is not using any loading state. So when the component is mounted and starts making ajax calls, events is undefined. You need to put a condition over there like this:
import React from 'react'
const Menu = ({events}) => {
console.log(events);
return events ? (
<div>
{events.map((event)=>{
return( <div key={event.category}>
<h3>{event.category}</h3>
</div>)
})}
</div>
) : null
}
export default Menu
//App.js file
import {ChatEngine} from "react-chat-engine";
import './App.css';
import ChatFeed from "./components/ChatFeed";
const App =()=> {
return (
<ChatEngine
height="100vh"
projectID="0e3104a3-d472-4764-9990-2845352801b9"
userName="Admin"
userSecret="123123"
renderChatFeed={(chatAppState) => <ChatFeed {...chatAppState}/>}
//renderChatFeed={(chatAppProps)=>{ return <ChatFeed {...chatAppProps}/>}}
/>
);
}
//ChatFeed component file
const ChatFeed = (props) => {
console.log(props);
return (
<div>
ChatFeed
</div>);
}
export default ChatFeed;
i am using a custom chatFeed component using renderChatFeed function but the chat feed component does not stop rendering i dont understand whats the issue
I am trying to render data from http://www.colr.org/json/color/random.
I use axios to GET data from API.
When I receive data, i cannot render it trhough the map (because it is obviously an array inside object) so it throws error:
TypeError: this.props.colors.map is not a function.
Do I need to use JSON.parse() or what can I do ?
//App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import Color from './components/Color';
import './App.css';
import axios from 'axios';
class App extends Component {
state = {
colors: []
};
componentDidMount() {
axios.get('http://www.colr.org/json/colors/random/2')
.then(res => this.setState({
colors: res.data }))
}
render() {
console.log(this.state.colors);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<Color
colors={this.state.colors}
/>
</header>
</div>
);
}
}
export default App;
//Color component:
import React, { Component } from 'react';
class Color extends Component {
render() {
return this.props.colors.map((color) => (
<h1
key={color.id}
>
Color{color.id}: {color.hex}
</h1>
))
}
}
export default Color;
You're almost there. The data coming back from Colr.org isn't in the format you expected. Use console.log(this.state) to see what was retrieved. You mapped over the root data object returned. However, the colors you want are nested in the data.data.colors array.
Also, take a look at the Async/Await pattern to make sure your JSON data is back from the API before you try to render it.
This should work:
import React, { Component } from "react";
import logo from "./logo.svg";
import Color from "./components/Color";
import "./App.css";
import axios from "axios";
class App extends Component {
state = {
colors: []
};
async componentDidMount() {
const apiResults = await axios.get("http://www.colr.org/json/colors/random/2");
this.setState({
colors: apiResults.data.colors
});
}
render() {
console.log(this.state);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<Color colors={this.state.colors} />
</header>
</div>
);
}
}
export default App;
you can use JSON.stringify it will convert it into string or you can use util library it works for me i worked on the same issue last day
I've been struggling with this for a couple days, and any help would be appreciated.
In this component, I have tried to do an HTTP call to my server and database. After parsing the response, using JSON.parse, I am getting back a correctly formed JSON object. I then want to map through that object and for each return a new component (called HistoryItem).
The code below attempts to do this by placing the object into the component state, but it is causing an infinite refresh loop. Previously I had tried a functional component.
The original iteration of this component did work. But it pulled a static JSON object from my client side files. Therefore, I am confident code works without the http call.
It seems to me I am doing something wrong with the async, which is disallowing the JSON object received asynchronously from being rendered.
Below is the main component. Note the component imports the username from redux. This feeds the HTTP call, so that it retrieves only records associated with the logged in user. Again, everything looks fine on the server/database end...
import React, {Component} from 'react';
import style from './history.css';
import HistoryItem from './HistoryItem/historyItem';
import data from '../../config/fakermyhistory.json';
import {Link} from 'react-router-dom';
import {connect} from 'react-redux';
import axios from 'axios';
class History extends Component {
constructor(props) {
super(props);
this.state = {
compiledList:[]
}
}
getData(){
this.state.compiledList.map((call, i) => {
const shaded = (call.rated) ? 'lightgrey' : 'white';
console.log("shaded", shaded);
return(
<Link to={`/reviewpage/${call._id}`} key={call._id}
style={{ textDecoration: 'none', color:'lightgrey'}}>
<div style={{backgroundColor:shaded}}>
<hr/>
<HistoryItem call={call}/>
</div>
</Link>
)
})
}
render(){
axios.post('/api/history', {username: this.props.username})
.then((res) => {
const array = JSON.parse(res.request.response);
this.setState({compiledList: array})
console.log("res", array);}
).catch((err) => console.log("err", err));
return (
<div className={style.container}>
<div className={style.historyHeader}>
<div className={style.historyHeaderText}>
Your Call History
</div>
</div>
<div className={style.historyList}>
{this.getData()};
</div>
</div>
)
}
}
const mapStateToProps = state => {
return {
username:state.auth.username
};
}
export default connect(mapStateToProps, null)(History);
Thanks in advance if you can help.
Here is another version using it as a functional component. Also doesn't render (although no errors on this one)
import React, {Component} from 'react';
import style from './history.css';
import HistoryItem from './HistoryItem/historyItem';
import data from '../../config/fakermyhistory.json';
import {Link} from 'react-router-dom';
import {connect} from 'react-redux';
import axios from 'axios';
const History =(props)=> {
const getData=(props)=>{
console.log("props", props);
axios.post('/api/history', {username: props.username})
.then((res) => {
const array = JSON.parse(res.request.response);
console.log("array", array);
array.map((call, i) => {
const shaded = (call.rated) ? 'lightgrey' : 'white';
console.log("shaded", shaded);
return(
<Link to={`/reviewpage/${call._id}`} key={call._id}
style={{ textDecoration: 'none', color:'lightgrey'}}>
<div style={{backgroundColor:shaded}}>
<hr/>
<HistoryItem call={call}/>
</div>
</Link>
)
})
}
).catch((err) => console.log("err", err));
}
return (
<div className={style.container}>
<div className={style.historyHeader}>
<div className={style.historyHeaderText}>
Your Call History
</div>
</div>
<div className={style.historyList}>
{getData(props)};
</div>
</div>
)
}
const mapStateToProps = state => {
return {
username:state.auth.username
};
}
export default connect(mapStateToProps, null)(History);
Instead of calling axios in render function, try to invoke it from componentDidMount.
This will help you prevent the infinite loop.
To return the components rendered within the map function, it was necessary to add a "return" command before the map function was called:
return array.map((call, i) => {...
I have got a problem with my app. Everything is fine untill I press the refresh button. I assume it is happening because of some stuff is not ready to be rendered yet.
import React from 'react'
import { Meteor } from 'meteor/meteor'
import { createContainer } from 'meteor/react-meteor-data'
import { withRouter } from 'react-router'
import LeftNavbar from '../dashboard/LeftNavbar'
import UpperBar from '../dashboard/UpperBar'
import NewGreetingsForm from './NewGreetingsForm'
import ConfigureButtons from './ConfigureButtons'
import Fanpages from '../../../api/Fanpages.js'
import './Greetings.scss'
export class Greetings extends React.Component {
constructor (props) {
super(props)
this.fanpage = this.props.user.profile.fanpages
this.state = {
newGreetingsText: '',
newGreetingsCharCount: 0
}
}
componentDidMount () {
}
render () {
const currentFanpage = Fanpages.findOne({fanpageName: this.fanpage})
const currentGreeting = currentFanpage.fanpageInfo.fanpageInfo.config.greeting[0].text
return (
<div className='container page'>
<UpperBar title={'Konfiguracja fanpage / Zdefiniuj greetings'} />
<LeftNavbar />
<div className='main-content'>
<h4 id='main-title'>{this.fanpage}</h4>
<div className='container'>
<div className='row'>
<ConfigureButtons />
<div>
<h5 id='configure-content-right'>Zmień obecną informację</h5>
<NewGreetingsForm fanpageName={this.fanpage} placeholder={currentGreeting} />
</div>
</div>
</div>
</div>
</div>
)
}
}
export default withRouter(createContainer(() => ({
user: Meteor.user()
}), Greetings))
Any idea where I should move those variables from render method? So it works as it should after page refresh? Thanks a lot for any participation.
Assuming there's subscription management going on above this component you can just defend against the data not being ready:
render () {
const currentFanpage = Fanpages.findOne({fanpageName: this.fanpage});
if (!currentFanpage) {
return (
<div />
);
} else {
const currentGreeting = currentFanpage.fanpageInfo.config.greeting[0].text
return (
// your html
)
}
}
Better yet, have the parent component render a spinner until the subscription is .ready()
Update
You asked about using createContainer with withRouter. I don't normally use withRouter and I haven't tested this but it should go something like:
const container = () => {
const sub = Meteor.subscribe('mysub');
const loading = sub.ready();
const user = Meteor.user();
return { loading, user };
}
export default withRouter(container, Greetings))
The important thing being that the container have a loading key that's tied to the state of the subscription.
Container tutorial