For some reason my map function is not returning anything in the render.
Basically I have a function that does a scrape with cheerio and then it stores the results in an array, then sets the state with it. When I check the react tools it shows that the state is updated with the array as expected. However, when the map function does not render anything and is blank on the screen.
I used very similar code in my last project but it's not working here, I feel I'm missing something simple but can't figure it out.
Here's the code:
import React, { Component } from 'react';
import { Trender } from '../Trender/trender';
import request from 'request';
import cheerio from 'cheerio';
export class Reddit extends Component {
constructor(props) {
super(props);
this.state = {
reddit: [],
ready: 0
}
this.getRedditTrending = this.getRedditTrending.bind(this);
}
getRedditTrending = () => {
var results = [];
request('http://old.reddit.com/r/leagueoflegends', function(error, response, html) {
var $ = cheerio.load(html);
console.log('hi')
$("p.title").each(function(i, element) {
var link = 'https://reddit.com' + $(element).children().attr("href");
var title = $(element).children().text();
console.log('hit')
results.push({
link: link,
title: title
})
})
})
this.setState({
reddit: results,
ready: 1,
})
}
componentDidMount(){
this.getRedditTrending()
}
render(){
if (this.state.ready == 1) {
return (
<div>
{<div>{this.state.reddit.map((i, item) => (<div>
<div key={i}>{item.title} </div>
</div>))}</div>}
</div>
)
}
else { return <div>hi</div>}
}
}
It's not giving me an error either. The map function doesn't show anything, but when I replace it with random text like "hello", that does get shown. Appreciate any advice, thanks.
Related
I'm experiencing an error "InternalError: too much recursion" when trying to push from my Layout to a Post site.
Code of Layout.vue:
watch(searchText, (newValue, oldValue) => {
log('Current State of SearchText', newValue);
if (newValue !== null) {
if (newValue.value !== undefined) {
let id = newValue.value;
// push to post with id
router.push(`/post/${id}`);
} else {
// todo: start search
}
}
});
I'm using the watch to react when my QSelect model value is changing.
My route:
{ path: '/post/:id', component: () => import('pages/Post.vue'),
My Post-page:
<template>
<q-page class="">
<Post // I'm getting no error when deleting this Component
:description="post.description"
:title="post.title"
:author="post.user"
:date="post.date"
:tags="post.tags"
:commentArray="post.comments"
/>
<h1>
Test
</h1>
</q-page>
</template>
<script>
import Post from 'src/components/PostComp.vue';
import { useRouter, useGetters, useActions } from '#u3u/vue-hooks';
import { ref } from '#vue/composition-api';
import moment from 'moment';
const debug = require('debug');
const log = debug('app:PostPage');
export default {
name: 'Post',
components: {
Post,
},
setup() {
const { route } = useRouter();
const post = ref({});
const getters = {
...useGetters('post', ['post']),
};
const actions = {
...useActions('post', ['findAll']),
};
log('params:', route.value.params);
const p1 = getters.post.value(route.value.params.id);
post.value = {
title: p1[0].title,
user: 'Mary Sullyman',
description: p1[0].description,
tags: p1[0].postTags,
comments: p1[0].commentDTOList,
date: moment(p1[0].createdDate).format('DD.MM.YYYY HH:mm') + ' Uhr',
};
log(post);
What I'm trying to do:
I have a QSelect in my Toolbar to search for posts which works just fine. Now I'm trying to push to a dynamically generated site for the post clicked.
What if you remove name: 'Post' (from export default)? The name you set matches the component tag name, so it falls into an infinite render loop.
See Recursive Components (still applies to Vue 3 even though it's from Vue 2 docs)
I am implementing a Welcome Display web app that takes a guest name received from RabbitMQ and populates it on the screen. In the callback function of the stompClient.subscribe(... I want to call the function to change the state of the reservation and view on the screen. When I call the function it says the function is not defined. How can I change the state every time I receive the message?
import React from 'react';
import '../css/App.css'
import WelcomeVisitor from '../pages/WelcomeVisitor';
import ThankYou from '../pages/ThankYou';
import Stomp from 'stompjs'
class App extends React.Component {
constructor(props){
super(props)
this.state = {
currentView: 'ThankYou',
currentReservation: null
}
this.siteId = props.match.params.siteId
this.bayNumber = props.match.params.bayNumber
this.changeView = this.changeView.bind(this)
this.connectRabbit = this.connectRabbit.bind(this)
}
changeView(view){
this.setState({
currentView: view
})
}
changeReservation(reservation){
this.setState({
currentReservation: reservation
})
}
render(){
let view = ''
this.connectRabbit(this.siteId, this.bayNumber)
if(this.state.currentView === 'ThankYou'){
view = <ThankYou changeView={this.changeView}/>
} else if(this.state.currentView === 'WelcomeVisitor') {
view = <WelcomeVisitor guestName='Quinton Thompson'/>
}
return (
<div className="App">
{view}
</div>
)
}
connectRabbit(siteId, bayNumber){
let stompClient
var ws = new WebSocket('ws://localhost:15674/ws')
const connectHeaders = {
'login': 'guest',
'passcode': 'guest',
}
const queueHeaders = {
'x-queue-name': `${bayNumber}.visit.out.display`,
'durable': 'true',
'auto-delete': 'false'
}
stompClient = Stomp.over(ws)
stompClient.connect(connectHeaders , function(frame){
console.log('Connected')
stompClient.subscribe('/exchange/ds.game/visit.out',function(message){
//changeReservation and changeView is not defined
this.changeReservation(message.body)
this.changeView('WelcomeVisitor')
}, queueHeaders)
console.log('here')
})
}
}
export default App;
The this object in your function callback is likely not referencing the this object in your class.
Changing the function syntax to: (message) => {} and (frame) => {} should make it work. See below:
stompClient.connect(connectHeaders ,(frame) => {
console.log('Connected')
stompClient.subscribe('/exchange/ds.game/visit.out', (message) => {
//changeReservation and changeView is not defined
this.changeReservation(message.body)
this.changeView('WelcomeVisitor')
}, queueHeaders)
console.log('here')
})
While the code snippet above would make your code work,
ideally we should avoid writing these types of callback initializations on the fly ( in render method ), maybe better way of doing it would be creating function calls and referencing those as callbacks. Something like this ( more improvements can be made but just as an example ) :
connectCallback(stompClient, queueHeaders, frame) {
console.log('Connected');
stompClient.subscribe('/exchange/ds.game/visit.out', (message) => {
this.subscribeCallback(message)
}, queueHeaders);
}
subscribeCallback(message) {
this.changeReservation(message.body)
this.changeView('WelcomeVisitor')
}
Then just use the two functions above as a callback in your render code.
Lastly, you might need to bind changeReservation(reservation) also before anything else.
I am making a react app which fetches and displays some CSV file data from the public folder. My react container looks like this:
import React, { Component } from 'react'
import * as Chart from "chart.js";
import { connect } from 'react-redux'
import { Bar } from 'react-chartjs-2'
import * as actions from "../actions"
import * as Papa from 'papaparse'
function mapStateToProps({stats}) {
return {
data: stats.data
}
}
class Stats extends Component {
fetchCsv(fileName) {
return fetch(fileName).then(function (response) {
let reader = response.body.getReader();
let decoder = new TextDecoder('utf-8');
return reader.read().then(function (result) {
return decoder.decode(result.value);
});
});
}
constructor(props){
super(props);
}
async componentDidMount() {
let PlayerArray = [], BallByBallArray = [], MatchArray = [],
PlayerMatchArray = [], SeasonArray = [], TeamArray = [];
let PlayerMatchData = await this.fetchCsv("Player_Match.csv");
Papa.parse(PlayerMatchData, {
complete: function(results) {
console.log("Finished:", results.data);
PlayerMatchArray = results.data;
console.log("entries.length: " + results.data.length);
}
});
}
render() {
return (
<div>
</div>
)
}
}
export default connect(
mapStateToProps, actions
)(Stats)
This is fetching the content of Player_Match.csv file using the fetchCsv function asynchronously and storing it in PlayerMatchData variable.
Then PlayerMatchData is being parsed by papaparse. The issue is that the file has 12700 entries in it and it is only fetching 3776 entries in google chrome.
Also, strangely it is fetching 1660 entries in firefox
Any input will be appreciated. :)
Edit: Link to the data: https://www.kaggle.com/harsha547/indian-premier-league-csv-dataset#Player_Match.csv
Okay, so I got the answer. As told by #SergiuParaschiv reader.read() only reads one chunk of data. So I instead used the fetch function to complete the task. There was no issue in the parsing.
await fetch("Player_Match.csv")
.then(response => response.text())
.then(text => {
PlayerMatchData = text;
// console.log(text)
})
This will do the task.
I'm a beginner in React and Redux. I've been working on this project where I finally figured out how to store an array as a state. Now, the only problem I'm having is, trying to figure out how to pass that state to another file.
Here are the two files
-Hue.js
-ColorShop.js
In Hue.js, I made an API and saved the contents into an array of objects called productJSON
Hue.js
class Hue extends React.Component {
constructor() {
super();
this.state = {
productJSON: []
};
}
componentWillMount() {
fetch('numberendpoint.json')
.then(results => {
return results.json();
}).then(data => {
let colorArray = [] //initialize array to receive json data
for (let i =0; i < data.length; i++) {
colorArray.push(data[i])
}
let productJSON = JSON.stringify(productArray)
this.setState({productJSON: productJSON});
})
}
render() {
return (
<div>
<div className="container2">
{this.state.productJSON}
</div>
</div>
)
}
}
Now, I'm trying to pass productJSON to another file in the same folder, ColorShop.js. I need to replace _colors (which was reading from a static json file) with productJSON.
ColorShop.js
import Hue from './Hue.js'
const TIMEOUT = 100
Hue productJSON={this.state.productJSON} <---- my attempt to get it to work
export default { // I need to replace '_colors' with productJSON
getColors: (cb, timeout) => setTimeout(() => cb(_colors), timeout || TIMEOUT),
}
I don't want to make another class in ColorShop.js, I just want to import this.state.productJSON into it, is that possible? Any pointers are greatly appreciated!!
Update: used the solution suggested by Rahamin. Now I have this code below, all contained within the the "Hue" class. But I'm still getting errors.
import React from 'react'
const TIMEOUT = 100
let productJSON;
class Hue extends React.Component {
constructor() {
super();
this.state = {
products: [],
};
this.getColors = this.getColors.bind(this)
}
componentDidMount() {
fetch('http://tech.work.co/shopping-cart/products.json')
.then(results => {
return results.json();
}).then(data => {
let colorArray = []
for (let i =0; i < data.length; i++) {
colorArray.push(data[i])
}
console.log("jsonproduct=" + JSON.stringify(productArray))
productJSON = JSON.stringify(colorArray)
this.setState({productJSON: productJSON});
});
}
render() {
return (
<div>
<div className="container2">
{this.state.productJSON}
</div>
</div>
)
}
}
export default {
getColors: (cb, timeout) => setTimeout(() => cb(({ productJSON: value})), timeout || TIMEOUT), // here is where I am getting an error -- "value" is undefined. I'm not sure I was meant to put "value" there or something else...very new to React so its conventions are still foreign to me.
}
What do you want to do? If the 'other file' is a helper function, you can just pass it a parameter, as you do in any function in any programming language:
From Hue you call colorShop(productsJson) and get back a result that you can render in Hue (colorShop starting with a lowercase character, otherwise React will think it is a component). It seems that the 'other file' can just be a function in the Hue.js file...
ColorShop can also be a component that gets productsJson as a prop and renders it after modification. ColorShop doesn't need to be a class, it can be a functional component. But this doesn't seem to be required by your example.
Here is the code (not complete - see comments) after inserting colorShop as a function into the class component. And you can pass it a value and get a returned value, or have it set the state, whatever you like:
import React from 'react';
const TIMEOUT = 100;
class Hue extends React.Component {
constructor() {
super();
this.state = {
productJSON: []
};
this.getColors = this.getColors.bind(this);
}
componentWillMount() {
fetch('numberendpoint.json')
.then(results => {
return results.json();
}).then(data => {
let colorArray = []; //initialize array to receive json data
for (let i = 0; i < data.length; i++) {
colorArray.push(data[i]);
}
let productJSON = JSON.stringify(productArray);
this.setState({ productJSON: productJSON });
});
}
render() {
// call getColor from wherver you need to call it.
// for example:
// getColors();
return (
<div>
<div className="container2">
{this.state.productJSON}
</div>
</div>
);
}
getColors(cb, timeout) {
setTimeout(() => cb(colors), timeout || TIMEOUT);
// Here you can setState({ productJSON: value });
// Or you can return a value to the caller
}
I am trying to obtain and display data in a React app from the samhsa.org API. I am able to console.log an XML string though I cannot seem get the node values. I have exhausted the last week trying to figure this out. Forgive me, I am learning React and not experienced with XML.
When I run:
import React from 'react';
import axios from 'axios';
import PropTypes from 'prop-types';
import { parser, parseString } from 'xml2js';
function ResourcesGrid(props) {
return (
<div>
<ul className='resources-list'>
{props.resources.map((resource) => {
return (
<li key={resource.title} className='resource-item'>
<ul className='space-list-items'>
<li>{resource.description}</li>
</ul>
</li>
)
})}
</ul>
</div>
)
}
ResourcesGrid.propTypes = {
resources: PropTypes.array.isRequired
}
export default class Resources extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
componentDidMount () {
let xml = 'http://content.samhsa.gov/ext/api/items?q-taxo=PanicDisorders~Recovery';
return axios.get(xml)
.then(function (res) {
console.log(res.data);
return res.data;
});
this.setState = {
resources: resources
}
}
render() {
return (
<div>
{!this.state.resources
? <p>LOADING...</p>
: <ResourcesGrid resources={this.state.resources} />
}`enter code here`
</div>
)
}
}
I get an object an object that contains a XML string:
When I log res.data I get a string.
I can't figure out how to get to the next level (EX: res.data["description"]).
I have tried 'xml2js':
componentDidMount () {
let xml = 'http://content.samhsa.gov/ext/api/items?q-taxo=PanicDisorders~Recovery';
return axios.get(xml)
.then(function (res) {
parser.parseString(res, function(err,result){
resData = result['data'];
console.log(resData);
});
return resData;
});
this.setState = {
resources: resources
}
}
and get TypeError: Cannot read property 'parseString' of undefined:
I've tried to convert it to JSON as well.
Am I way off? I need help!