I'm making two separate requests to different APIs to receive the [Bitcoin/USD] and then [GBP/USD]. I'm using axios to setup a promise, and on both calls successfully resolving, I'm setting both values to state set.State{}.
I'm trying to calculate the exchange rate between GBP/Bitcoin, but for the life of me can't wrap my head around how best to do it. It's also been a little while since I've used React, so any advice on improving what I've got would be great.
app.js
import React, { Component } from 'react';
import './App.css';
import axios from 'axios';
class App extends Component {
constructor(props) {
super(props);
this.state = {
conv: [],
GBP: [],
XBT: [],
};
}
componentDidMount() {
axios.all([this.getXbt(), this.getGbp()])
.then(axios.spread( (xbtValue, gbpValue) => {
const XBT = xbtValue.data.bpi.USD.rate_float;
const GBP = gbpValue.data.rates.GBP;
const conv = this.calcConversion(GBP, XBT);
this.setState({conv, GBP, XBT});
}));
}
calcConversion(x, y) {
// Calculate conversion value here
return x / y;
}
getXbt() {
return axios.get('https://api.coindesk.com/v1/bpi/currentprice/XBT.json');
}
getGbp() {
return axios.get('https://openexchangerates.org/api/latest.json?app_id=#API_KEY#');
}
render() {
return (
<div className="App">
<div id="crypto-conversion">
<span className="left">{this.state.conv}</span>
</div>
<div id="crypto-container">
<span className="left">{this.state.GBP}</span>
<span className="right">{this.state.XBT}</span>
</div>
</div>
);
}
}
export default App;
Assuming the APIs are returning the data as GBP/1USD and USD/1XBT, then the conversion rate is simply the product of the two values and will result in GBP/1XBT.
It's also been a little while since I've used React, so any advice on improving what I've got would be great.
Your code looks fine so far. I like the way you handled the API calls, and the setState() call follows convention as far as only calling it once.
Edit:
Also, I've just realized if you're willing to shell out $95/mo, the Open Exchange Rates API provides a /convert endpoint that supports BTC.
Related
I'm starting to develop with React, I went through React Native first, so I'm a bit used to their ideas.
What's my problem with these structures:?
Performance, speed.
I wonder since then.
An example ? I realized when presented some mobile animations, they performed horrible when used in synchronous modes.
Maybe I didn't know the framework in an advanced way to understand it and extract its potential, but as you know, using it leaves you in the dark in some parts.
I'll leave here an example of how I reproduced this difference in speed between 'Vanilla JS' and React.JS.
React.JS
I'm just using an API to get all countries (250) and display them after the call.
This is the code: Main-> Container-> List-> Country,
I also used Styled Components, FontAwasome.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import './api.js'
import styled from "styled-components";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { library } from "#fortawesome/fontawesome-svg-core";
import { faUser } from "#fortawesome/free-solid-svg-icons";
class Country extends React.Component {
clickChild = () => {
this.props.clicked(this.props.name)
}
render() {
return (
<Box onClick={this.clickChild} className="content">
<ImageBox flag={this.props.flag}>
<Icon num={this.props.num}><FontAwesomeIcon icon="user"/></Icon>
</ImageBox>
</Box>
);
}
}
class Lista extends React.Component {
constructor(props) {
super(props)
this.state = {lista:[]}
}
componentDidMount(){
let lista_temp = []
console.log("Iniciando requisição !")
fetch("https://restcountries.eu/rest/v2/all")
.then(resp => resp.json())
.then((json_data)=>{
for(var i=0;i<json_data.length;i++){
var population = (json_data[i].population).toLocaleString(undefined,{minimumFractionDigits: 0})
lista_temp.push({flag:json_data[i].flag,name:json_data[i].translations.br,num:population})
}
this.setState({lista:lista_temp})
console.log("Concluído !")
});
}
click(name){
window.open('https://pt.wikipedia.org/wiki/'+name,"_blank")
}
render() {
return (
<div className="lista">
{this.state.lista.map((tile,index) => (
<Country key={index} flag={tile.flag} name={tile.name} num={tile.num} clicked={this.click}/>
))}
</div>
);
}
}
class Container extends React.Component {
render() {
return (
<div className="container">
<div className="main_contant">
<Lista/>
</div>
</div>
);
}
}
class Main extends React.Component {
render() {
return (
<Container/>
);
}
}
// ========================================
ReactDOM.render(
<Main />,
document.getElementById('root')
);
When we look at the List component, do we have the use of Hooks? I can't say exactly what happens with this use, it seems to be the cause of the problems. Hooks are theoretically not supported in class components.
When we look at its usage, notice that I refresh the list after the entire API is complete, but I can make it much worse by calling setState on each loop item.
this.setState ({list: [... this.state.lista, {flag: json_data [i] .flag, name: json_data [i] .translations.br, num: population}]})
Here are the comparisons in terms of numbers.
A note: I won't put the Vanilla code (I'll leave a link if you like), but I'll show you its interface. It has a lot more interaction than React.
In React there is just one click of the event. In vanilla we have animations, autocomplete, consumption of another API and other events. And basically it's an '.append' html for each item consumed by the API.
I don't know why, but I changed the code to post here, and I realized there was an improvement, I don't understand, before it was between 6s - 9s, now it's 4s.
Vanilla
React and broken instruction;
What's wrong with my learning from this framework, any direction?
https://github.com/ricardosc12/stack_ask
I've been working on a small project for the last of months now involving using functional components and hooks to make an API call and extract some data and do something things with said data. I started with have 1 file that held 3 components in it and was based on classes. I moved everything to functional components and slowly started to build more files. Now, I'm on to my final part of learning React on the side and that comes with Redux. I was wondering if anyone could give me some advice on where to start refactoring my code for Redux and any useful tools out there that may help me along the way. At its core this is a small project but I want to keep the code evolving much like I've evolved through out this.
Below is a component and a .services that handles the API call. This is basically the whole project in a nutshell.
HeroDetails.js
import React, {useState, useEffect} from "react"
import "../App.css"
import {fetchHeroDetail} from './services/HeroDetail.services'
import { useParams } from 'react-router-dom'
function HeroDetail() {
const { id } = useParams()
const [hero, setHero] = useState({})
useEffect(() => {
fetchHeroDetail(id).then(hero => {
setHero(hero);
});
}, [id]);
return(
<div>
<h1>{hero.localized_name} </h1>
<h2>{hero.move_speed}</h2>
<h2>{hero.base_health}</h2>
</div>
)
}
export default HeroDetail
HeroDetail.services.js
import React from 'react'
export const fetchHeroDetail = async (id) => {
const data = await fetch(`https://api.opendota.com/api/heroStats`)
console.log(data)
const heroDetails = await data.json()
console.log(heroDetails)
console.log(heroDetails.find(heroDetail => heroDetail.id === +id))
return heroDetails.find(heroDetail => heroDetail.id === +id)
};
I'm currently working on using React to upload a CSV file and convert the data to an array so I can access phone numbers. I've actually got it almost completely functional, with just one problem: I can't figure out how to store the array properly in a variable (dataDump) on the global level. It stores it inside another array.
Here's a picture of my console so you can see what I mean.
I'm able to access the contents of dataDump if I use dataDump[0] (as seen in the function for handleClick), but that won't work for a global variable. I need to be able to send the array's values to other components/files, so I don't think having to call it like that will work. Chances are I'm over-complicating this in my head and the answer is incredibly simple, but I've spent the past 2-3 weeks learning React, Twilio, Mongodb etc. from scratch so my brain's not cooperating.
I'll appreciate any help! Thanks! Code below. (Note this is a component that's imported to the App page.)
import React from "react";
import CSVReader from "react-csv-reader";
var dataDump = [];
console.log(dataDump);
const papaparseOptions = {
header: true,
dynamicTyping: true,
skipEmptyLines: true,
transformHeader: header => header.toLowerCase().replace(/\W/g, "_"),
complete: function(results) {
dataDump.push(results.data);
console.log(dataDump);
var rows = results.data;
let numbers = rows.map(a => a.phone_number); //make the results ONLY the phone numbers
// console.log(numbers);
document.getElementById("data2").innerHTML=numbers; //display the phone numbers
}
};
class Import extends React.Component {
constructor(props) {
super(props);
this.state = {data:[]};
this.handleClick = this.handleClick.bind(this);
}
handleForce = data => {
// console.log(data.length);
console.log(data);
this.setState({data: data});
};
handleClick = () => {
console.log("success");
console.log(this.state.data);
console.log("Next is Numbies:");
let numbies = dataDump[0].map(a => a.phone_number);
console.log(numbies);
document.getElementById("data").innerHTML=numbies;
}
render() {
return (
<div className="container">
<CSVReader
className="csv-input"
label="Select CSV file to import"
onFileLoaded={this.handleForce}
parserOptions={papaparseOptions}
/>
<div>
</div>
<button onClick={this.handleClick.bind(this)}>
Test
</button>
<div id="data" />
<div id="data2" />
<div id="data3">
</div>
</div>
);
}
}
export default Import;
// export default DataController;
Under the hood React-Redux is using context and hooks these days, so don't bother implementing a Redux stack until you've outgrown the simpler, React API, or at least you've fixed your issue. Folks joke that Redux is like shooting a fly with a bazooka. More info on React-Redux internals here and here's the documentation for React's Context.
Some psuedo-code to get you on the right path:
// context.js
import { createContext } from 'react';
export const Store = createContext();
// app.js
import React from 'react';
import { Store } from './context';
import Import from './import'; // I wouldn't change the casing on or reuse a reserved keyword personally, maybe calling this something like 'CsvImporter' would be an improvement
function App() {
const [dataDump, setDataDump] = React.useState([]);
return (
<Store.Provider value={{ dataDump, setDataDump }}>
<Import dataDump={dataDump} setDataDump={setDataDump} />
</Store.Provider>
);
}
Now your import component has two new props, dataDump and setDataDump. You can call setDataDump just like any other call to setting state. Nice!
So you need the dataDump in a new component? That's easy peasy, lemon squeezy, and all without global variables or tossing module scoping to the side:
// foobar.js
import React from 'react';
import { Store } from './context';
export function Foobar() {
// you probably want to do more than force render an array as a string, but this is just a proof of concept
return (
<Store.Consumer>
{({ dataDump, setDataDump }) => (
<p>
`${dataDump}`
</p>
)}
</Store.Consumer>
);
}
Just make sure that Foobar or other components are rendered as children of the Provider in app.js and now you have a 'global' context for passing around dataDumps.
This should be super simple for some of you. I have a super simple app that I am making to teach myself the glory that is React and reactDom. Currently, I am pulling from an API (which actually works!), however, I am unable to see any data when rendering to the screen. Literally just two components. I am sure that I am using props or state wrong here, I just don't know where. It's possible that my map function is the problem as well.
Here is the code:
Parent:
import React from "react";
import ReactDOM from "react-dom";
import axios from 'axios'
import { Table } from './Table'
export class DataList extends React.Component {
state = {
articles: []
}
componentDidMount() {
axios.get('http://127.0.0.1:8000/api/portblog/')
.then(res => {
this.setState({
articles: res.data
})
console.log(res.data)
})
}
render() {
return(
<div>
<Table id={this.state.articles.id} articles={this.state.articles} />
</div>
)
}
}
export default DataList
And the child:
import React from "react";
import PropTypes from "prop-types";
import key from "weak-key";
export const Table = (props) => (
<div>
<h1>Welcome to the Article List Page Home</h1>
<li>{props.articles.map((article) => {
{article.titles}
})}</li>
</div>
);
export default Table;
The problem is that your map() call is not returning anything. You need to do something like:
<div>
<h1>Welcome to the Article List Page Home</h1>
{props.articles.map(article =>
<li>{article.titles}</li>
)}
</div>
I'm not exactly sure what your desired output is, but generally you map over data to generate a set of dom elements.
The problem is
<li>{props.articles.map((article) => {
{article.titles}
})}</li>
JSX expressions cannot be used in any arbitrary place. props.articles.map(...) is already an expression, so creating a new one wouldn't make sense.
{article.titles} inside a function creates a block that does nothing. Nothing is returned from map callback, the array isn't mapped to anything.
Depending on what should resulting layout look like, it should be either
<li>{props.articles.map((article) => article.titles)}</li>
output titles within single <li> tag, or
{props.articles.map((article) => <li>{article.titles}</li>)}
to output a list of <li> tags.
ESLint array-callback-return rule can be used to prevent the problem with callback return value.
So I'm having a go at my first React app using create-react-app, and I'm trying to make a multi-stage form based on this GitHub project. In particular the AccountFields and Registration parts.
That project seems to have been written in a much older version of React, so I've had to try and update it - and this is what I have so far:
App.js:
import React, { Component } from 'react';
import './App.css';
import Activity from './Activity';
var stage1Values = {
activity_name : "test"
};
class App extends Component {
constructor(props) {
super(props);
this.state = {
step: 1
};
};
render() {
switch (this.state) {
case 1:
return <Activity fieldValues={stage1Values} />;
}
};
saveStage1Values(activity_name) {
stage1Values.activity_name = activity_name;
};
nextStep() {
this.setState({
step : this.state.step + 1
})
};
}
export default App;
Activity.js:
import React, { Component } from 'react';
class Activity extends Component {
render() {
return (
<div className="App">
<div>
<label>Activity Name</label>
<input type="text" ref="activity_name" defaultValue={this.props.stage1Values} />
<button onClick={this.nextStep}>Save & Continue</button>
</div>
</div>
);
};
nextStep(event) {
event.preventDefault();
// Get values via this.refs
this.props.saveStage1Values(this.refs.activity_name.getDOMNode().value);
this.props.nextStep();
}
}
export default Activity;
I've looked at a number of examples, and this seems to be the right approach to store the current state (to allow users to go back and forth between different parts of the form), and to then store the values from this stage. When I click the Save & Continue button, I get an error saying Cannot read property 'props' of null. I mean obviously this means this is null, but I'm unsure of how to fix it.
Am I approaching this the wrong way? Every example I find seems to have a completely different implementation. I come from an Apache-based background, so this approach in general I find very unusual!
the this in nextStep isn't pointing to Activity and just do like this
<button onClick={()=>this.nextStep()}>Save & Continue</button>
Bind this to nextStep function:
<button onClick={this.nextStep.bind(this)}>Save & Continue</button>
Or in the constructor:
constructor(props){
super(props);
this.nextSteps = this.nextSteps.bind(this);
}