I want to pass data from axiosDidMount function to
<p className='title' id='boldTitle'>{data goes here}</p>
I can console.log data and it is working and in my example it is a string "New York City".
I got to the point when I write some input in Search.js Component and it is passed to Results.js Component by this.props.userQuery. So the response.data[1][1] is updating correctly and live in console.log as I write input but I have problem with passing this data that I'm getting from Wikipedia to final destination.
What is proper way to pass this data in this example?
import React from 'react';
import axios from 'axios';
export default class Results extends React.Component {
axiosDidMount(userQuery) {
//const fruits = [];
const wikiApiUrl = 'https://en.wikipedia.org/w/api.php?action=opensearch&format=json&origin=*&search=';
const wikiApiUrlWithQuery = wikiApiUrl + userQuery;
axios.get(wikiApiUrlWithQuery)
.then(response => {
console.log(response.data[1][1]); //New York City
console.log(typeof(response.data[1][1])); //string
//console.log(response.data[2])
//console.log(response.data[3])
//fruits.push(response.data[1]);
})
.catch(err => {
console.log('Error: =>' + err);
});
//return fruits;
}
render() {
//this.props.userQuery from Search.js
const test = this.axiosDidMount(this.props.userQuery);
return(
<div>
<a className='title' href="" target='_blank'>
<div className='result'>
<p className='boldTitle'>{data goes here}</p>
<p></p>
</div>
</a>
</div>
);
}
}
You should separate your concerns. Make a data receiving component, or a container component that handles data retrieval and conditionally renders the component requiring the data once it's available. Something along the lines of the following:
import React, { Component } from 'react';
import axios from 'axios';
const PresentationComponent = (props) => {
// return mark with data
}
const PlaceHolderComponent = (props) => {
// return placeholder markup
}
export default class DataReceivingWrapper extends Component {
constructor(props) {
super(props);
this.state = {
data: null
}
}
componentDidMount() {
axios.get(...)
.then(data) {
this.setState(Object.assign({}, this.state, { data: data }))
}...
}
render() {
if (this.props.data) {
return <PresentationComponent />;
} else {
return <PlaceHolderComponent />; // or null
}
}
}
Related
I'm trying to call a dictionary from Django Rest Framework API to view on my frontend. Using Django backend & Reactjs frontend. Through some research looks like i'm getting this error due to the map() function only accepting arrays, while my API is returning a dictionary (I THINK SO).
How do I fix this? I'm new to javascript & apologies in advance for the messy code. Please see my App.js below:
App.js
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
todoList: [],
}
this.fetchTasks = this.fetchTasks.bind(this)
};
componentWillMount() {
this.fetchTasks()
}
fetchTasks() {
fetch('http://127.0.0.1:8000/api/api-overview')
.then(response => response.json())
.then(data =>
this.setState({
todoList: data
})
)
}
render() {
var tasks = this.state.todoList
return (
<div className="container">
{tasks.map(function (task, index) {
return (
<div className="center-column">
<div className="item-row">
<div key={index} className="centered">
<span>{task.bitcoin_symbol}</span>
</div>
</div>
</div>
)
})}
</div>
);
}
}
export default App;
API response:
You're fetching a single object, not an array. .map() is a method which run over iterables(arrays, strings, etc - objects, that can be iterated over) and creates a new output element from each input one. In react we mainly use it to convert an item to its JSX(react/html) representation. As you're working over a single object, you should access it directly:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
bitcoinData = null
}
this.fetchBitcoinData = this.fetchBitcoinData.bind(this);
};
componentWillMount() {
this.fetchBitcoinData();
}
fetchBitcoinData() {
fetch('http://127.0.0.1:8000/api/api-overview')
.then(response => response.json())
.then(data =>
this.setState({
bitcoinData: data
});
);
}
getBitcoinRepresentation() {
var bitcoinData = this.state.fetchBitcoinData;
if (!bitcoinData) {
return <div>Loading...</div>;
}
else {
return (
<div className="container">
<div>{bitcoinData.bitcoin_symbol}</div>
<div>{bitcoinData.bitcoin_price}</div>
<div>{bitcoinData.bitcoin_dailychangeinprice}</div>
</div>
);
}
}
render() {
return getBitcoinRepresentation();
}
}
export default App;
I am getting values from locaStorage through this file:
const cartDataFn = () => {
let cartData = []
const cartDataStorage = JSON.parse(localStorage.getItem('cartList'))
if (cartDataStorage !== null) {
cartData = cartDataStorage
}
return cartData
}
export default cartDataFn
OUTPUT:
As you see it is a function which returns an array (cartData)
If I import it into a function component I am able to get the array. Like this:
import React, { Fragment } from 'react'
import cartData from '../../../Data/cartData';
const Products = props => {
let [cartState, setCart] = React.useState(cartData)
console.log(cartState) // => It prints the array cartData
}
export default Products
However, when I try to do the same with a class component I don't know how to get cartData. If I log the file into console I get a visual represention of the function.
import React, { Component } from 'react'
import cartData from '../../Data/cartData'
class Layout extends Component {
state = {
cartState: cartData,
}
componentDidMount(){
console.log(this.state.cartState) // => It wont give me 'cartData', rather I'll get a visual draw of the whole function
}
render () {
return (
<div>
<p>Anything</p>
</div>
)
}
}
export default Layout
OUTPUT:
How can I access these values in class components?
Since cartDataFn is a function, you need to invoke it in the class component:
class Layout extends Component {
state = {
cartState: cartData(),
}
(preferably, give it a more accurate name to indicate that it's a function, not data)
This is the first time I am using react. I am coming from jQuery to React this feels like a big jump. If anybody can help me refactor this to work the React way I will be forever in your debt! :)
I am trying to parse an RSS feed, where I want to grab the most recent post title and link to render into a component.
https://www.npmjs.com/package/rss-parser - Using this to get the parser.
When viewing my app in the browser the async function is spitting out the rss feed into the console, which is a good start I guess!
// src/App/index.tsx
import * as React from 'react';
import * as Parser from 'rss-parser';
// Types
import { string } from 'prop-types';
let parser = new Parser();
// blueprint for the properties
interface Props {
name: string;
}
// Component state
interface State {
//feed: any[];
}
(async () => {
let feed = await parser.parseURL('https://www.reddit.com/.rss');
console.log(feed.title);
feed.items.forEach((item: { title: string; link: string; }) => {
console.log(item.title + ':' + item.link)
});
})();
export default class App extends React.Component<Props, State> {
render() {
return (
<div>
<h1>RSS Feed</h1>
<div>
<h1>item.title</h1>
item.link
</div>
</div>
);
}
}
If I understand you right, you need something like this:
export default class App extends React.Component<Props, State> {
constructor(props: {}) {
super(props);
this.state = { feed: [] };
}
async componentDidMount() {
const feed = await parser.parseURL('https://www.reddit.com/.rss');
this.setState({ feed });
}
render() {
return (
<div>
<h1>RSS Feed</h1>
this.state.feed.map((item, i) => (
<div key={i}>
<h1>item.title</h1>
item.link
</div>
))
</div>
);
}
}
I faced the same problem and solved by this. if you don't check for "undefined" value. It will show you error because react renders page 2 times and you have an undefined array of feed.items in your hand when in first render.
My index.js file:
import React from 'react'
import {render} from 'react-dom';
let Parser = require('rss-parser');
let parser = new Parser();
const CORS_PROXY = "https://cors-anywhere.herokuapp.com/";
class App extends React.Component{
constructor(props) {
super(props);
this.state = {
feed: []
};
}
async componentDidMount() {
const feed = await parser.parseURL(CORS_PROXY + 'https://www.reddit.com/.rss');
this.setState(feed)
}
render() {
return (
<div>
<h1>Blog Posts</h1>
{this.state.items && this.state.items.map((items, i) => (
<div key={i}>
<h1>{items.title}</h1>
{items.link}
</div>
))}
</div>
);
}
}
render(
<App />,
document.getElementById("root")
)
I am building a simple movie catalogue using themoviedb API however I am facing an issue that I am unable to solve.
The issue is that the result after fetching is always undefined.
I tried with the method componentWillMount to fetching data and the setting the state inside this method but it does not work.
I tried to fetch inside constructor, no result.
This is my code so far
import React, { Component } from 'react';
import Header from './components/Header';
import MovieList from './components/MovieList';
import Footer from './components/Footer';
const MOVIE_API = "http://api.themoviedb.org/3/discover/movie?api_key=72049b7019c79f226fad8eec6e1ee889&language=en-US&sort_by=release_date.desc&include_adult=true&include_video=false&page=2&primary_release_year=2018";
//class
class App extends Component {
constructor(props){
super(props);
this.state = {
movies: [],
movieName: ''
}
}
componentWillMount(){
this.fetchMovie();
}
//fetching movie
fetchMovie = () =>{
const req = new Request(MOVIE_API, {
method: 'GET',
cache: 'default'
});
fetch(req).then(response =>{
return response.json();
}).then(data =>{
console.log(data); //REF 1;
this.setState({
movies: data
});
}).catch(err => {
console.log("ERROR: " + err);
})
}
render() {
return (
<div className="root">
<Header />
<MovieList moviesRes={this.state.movies}/>
<Footer />
</div>
);
}
}
export default App;
As you can see I called the method componentWillMount to fetch the data but it does not work.
It is also noticeable that if I log the data (REF 1) I can see the result (json).
===========================
EDIT
This is the code for MovieList
/*import React, { Component } from 'react';
export default class MovieList extends Component{
constructor(props){
super(props);
this.state = {
movies: this.props.movieRes
}
}
render(){
//if result is undefined
if(this.state.movieRes === undefined){
return(
<h1>Loading...</h1>
);
}else{
return(
<ul>
{this.state.movieRes.map((movie, index)=>{
return (
<li key={index}>{movie.title}</li>
);
})}
</ul>
);
}
}
}*/
=================
update child code
import React, { Component } from 'react';
export default class MovieList extends Component{
render(){
const { movieRes = [] } = this.props; // we are assigning a default prop here of an empty array.
return(
<ul>
{
//return movie from array
movieRes.map((movie, index)=>{
return (
<li key={index}>
{movie.id}
</li>
);
})
}
</ul>
);
}
}
In this I way I suppress the error, but still it is not working.
From what I learnt, React should render as soon as it detect changes but for some reason it not the case.
IMAGE
As you can see from the image when I am passing the array from parent component to the child component the array length is 20 but in the child component the array length seems to be 0
===================
Solution
I changed the component from class to a const and pass to it the array and everything went smooth. Here is the final code:
import React from 'react';
const MovieList = ({movies}) =>{
if(!movies){
return <h1>Loading...</h1>
}
return (
<ul>
{
movies.map((movie, index) => {
return (
<li key={index}>
<p>{movie.title}</p>
</li>
)
})
}
</ul>
);
}
export default MovieList;
Originally I misunderstood your issue but after re-reading it I noticed that you defined movies as an array in your constructor.
Without an actual error message, I'm going to assume that MovieList is expecting an array for it's prop movieRes and you're probably then trying to do something like .map or a loop to render the movies.
However, the API you're using doesn't return an array. It returns an object with an array key'd under results. So, I changed it to access data.results when doing setState.
//fetching movie
fetchMovie = () =>{
const req = new Request(MOVIE_API, {
method: 'GET',
cache: 'default'
});
fetch(req).then(response =>{
return response.json();
}).then(data =>{
console.log(data);
this.setState({
movies: data.results // <-- change made here.
});
}).catch(err => {
console.log("ERROR: " + err);
})
}
Here's a working JSFiddle:
https://jsfiddle.net/patrickgordon/69z2wepo/99513/
EDIT:
In the child component, instead of assigning props to state, just use props and default props.
import React, { Component } from 'react';
export default class MovieList extends Component{
render(){
const { movieRes = [] } = this.props; // we are assigning a default prop here of an empty array.
return(
<ul>
{movieRes.map((movie, index)=>{
return (
<li key={index}>{movie.title}</li>
);
})}
</ul>
);
}
}
I'm currently having a problem trying to get UI to render with React. I'm using information I've received from ShopifyAPI and trying to render it to my component. I'm not sure what to do. Do I need to update the state with information returned from my API? Here's my code at the moment.
ShopifyCatalog.js
import React, { Component } from 'react';
import { Link } from 'react-router'
import styles from '../styles';
import ShopProducts from './ShopProducts'
import { getAllProducts } from '../utils/shopifyHelpers';
export default class ShopCatalog extends Component {
constructor(...args){
super(...args);
this.state = {
allProducts: []
}
}
render() {
let allProducts
getAllProducts()
.then((products) => {
return allProducts = products
})
.then((allProducts) => {
allProducts.map((product) => {
<div className='col-sm-offset-1 col-sm-2'>
<Link to={'shop/${product.id}'}>
<img src={product.images[0].src} />
<h5>{product.title}</h5>
</Link>
</div>
})
})
return (
<div style={styles.productInfo}>
{allProducts}
</div>
)
}
}
I thought it might have something to do with using promises more extensively, but I'm pretty sure it's because my state isn't updating with the information that I'm grabbing from the API. I appreciate your time, thank you.
EDIT:
I've updated my code now and it looks like this
ShopCatalog.js Updated
import React, { Component } from 'react';
import { Link } from 'react-router'
import styles from '../styles';
import ShopProducts from './ShopProducts'
import { getAllProducts } from '../utils/shopifyHelpers';
export default class ShopCatalog extends Component {
constructor(...args){
super(...args);
this.state = {
allProducts: [],
listAllProducts: []
}
}
componentDidMount() {
getAllProducts()
.then((products) => {
this.setState({
allProducts: products
})
})
}
render() {
return (
<div style={styles.productInfo}>
{this.state.allProducts.map((product) => {
<h1>{product.title}</h1>
})}
</div>
)
}
}
But it's still not rendering anything from the map of my state. Is it because map is called while there is nothing in the state? How do I work around this so map get's called and returns UI? Thank you.
Put your request in the componentDidMount lifecycle method, then update your state. Your render method is returning before your request has completed.
export default class ShopCatalog extends Component {
constructor(...args){
super(...args);
this.state = {
allProducts: []
}
}
componentDidMount() {
const _this = this;
getAllProducts()
.then((products) => {
_this.setState({ allProducts: products });
});
}
render() {
return (
<div style={styles.productInfo}>
{this.state.allProducts.map((product) => {
<div className='col-sm-offset-1 col-sm-2'>
<Link to={'shop/${product.id}'}>
<img src={product.images[0].src} />
<h5>{product.title}</h5>
</Link>
</div>
})}
</div>
)
}
}
I assume something like this, not sure specifics to your case, just giving idea how this should look like.
export default class ShopCatalog extends Component {
state = {
allProducts: []
}
getAllProducts = () => {
fetch(...API).then(response => response.json()).then(products =>
this.setState({allProducts: products}));
}
componentDidMount() {
this.getAllProducts()
}
render() {
const {allProducts} = this.state;
return (
<div>
{allProducts.map((product,key) => <div key={key}>
<span>{product.title}</span>
</div>
)}
</div>
)
}
}