I have this Output component which should be rendered when it get props from the parent component.
How can I do this?
Right now, it renders when I click a button but without the getTranslate function getting called. In debugger I can see that the component has the props needed, it just doesn't run my getTranslate function
import React, { useState } from "react";
import Axios from "axios";
const Output = (props) => {
const [output, setOutput] = useState(null);
const [url, setUrl] = useState(null);
const getUrl = (language, text) => {
console.log("GetURL ran with: ", language, text);
let url = "";
switch (language) {
case "yoda":
url =
" https://api.funtranslations.com/translate/yoda.json?text=" + text;
break;
case "valyrian":
url =
"https://api.funtranslations.com/translate/valyrian.json?text=" +
text;
break;
case "sith":
url =
"https://api.funtranslations.com/translate/sith.json?text=" + text;
break;
case "shakespeare":
url =
"https://api.funtranslations.com/translate/shakespeare.json?text=" +
text;
break;
case "pirate":
url =
"https://api.funtranslations.com/translate/pirate.json?text=" + text;
break;
case "minion":
url =
"https://api.funtranslations.com/translate/minion.json?text=" + text;
break;
case "lolcat":
url =
"https://api.funtranslations.com/translate/lolcat.json?text=" + text;
break;
case "klingon":
url =
"https://api.funtranslations.com/translate/klingon.json?text=" + text;
break;
case "hacker":
url =
"https://api.funtranslations.com/translate/hacker.json?text=" + text;
break;
case "dothraki":
url =
"https://api.funtranslations.com/translate/dothraki.json?text=" +
text;
break;
default:
break;
}
setUrl(url);
};
const getTranslate = () => {
getUrl(props.language, props.text);
const axios = require("axios");
axios.get(function (respone) {
console.log("Here comes response from api call: ", respone);
return respone.contents.translated;
});
};
return (
<div>
<textarea placeholder="Translated..." value={{ getTranslate }}></textarea>
</div>
);
};
export default Output;
The probable problem is you are not calling getTranslate function, looks like it should be getTranslate(); also you need to update state once you receive data.. see I have placed comments to guide to towards a solution... getTranslate is not returning any value, and the place you are calling it not appropriate...
const getTranslate = () => {
getUrl(props.language, props.text);
const axios = require("axios");
axios.get(function (respone) {
console.log("Here comes response from api call: ", respone);
/// update the variable /state/ prop that you want to bind
return respone.contents.translated;
});
};
Then bind the value in template:
return (
<div>
<textarea placeholder="Translated..." value={ the value to bind from state/prop}></textarea>
</div>
)
;
To call getTranslate(), you can use hooks lifecycle method useEffect(). And value returned from this function can be set to some state and bind the set state to text area value.
import React, { useState, useEffect } from "react";
import Axios from "axios";
const Output = (props) => {
const [output, setOutput] = useState('');
const [url, setUrl] = useState('');
useEffect(()=>{
getTranslate();
})
const getUrl = (language, text) => {
console.log("GetURL ran with: ", language, text);
let url = "";
switch (language) {
case "yoda":
url =
" https://api.funtranslations.com/translate/yoda.json?text=" + text;
break;
case "valyrian":
url =
"https://api.funtranslations.com/translate/valyrian.json?text=" +
text;
break;
case "sith":
url =
"https://api.funtranslations.com/translate/sith.json?text=" + text;
break;
case "shakespeare":
url =
"https://api.funtranslations.com/translate/shakespeare.json?text=" +
text;
break;
case "pirate":
url =
"https://api.funtranslations.com/translate/pirate.json?text=" + text;
break;
case "minion":
url =
"https://api.funtranslations.com/translate/minion.json?text=" + text;
break;
case "lolcat":
url =
"https://api.funtranslations.com/translate/lolcat.json?text=" + text;
break;
case "klingon":
url =
"https://api.funtranslations.com/translate/klingon.json?text=" + text;
break;
case "hacker":
url =
"https://api.funtranslations.com/translate/hacker.json?text=" + text;
break;
case "dothraki":
url =
"https://api.funtranslations.com/translate/dothraki.json?text=" +
text;
break;
default:
break;
}
setUrl(url);
};
const getTranslate = () => {
console.log("From get translate")
getUrl(props.language, props.text);
Axios.get(function (respone) {
console.log("Here comes response from api call: ", respone);
setOutput(respone.contents.translated);
});
};
return (
<div>
<textarea placeholder="Translated..." value={output} onChange={()=>console.log("Testing")}></textarea>
</div>
);
};
export default Output;
You need to move your translate functionality to either the "onChange" function or the "onBlur" function (if you want the text to be translated after the user clicks out).
Also the functions you pass to onChange and onBlur should manage the async nature of your translate functionality.
You can use a useEffect Method which will run every time when props changes or component renders.
useEffect(()=>{
getTranslate();
}, [props])
Related
I am trying to pass a date from my react component to an async function so that the async function can change the date used in its API call.
To be more specific:
From the ChooseDate.js(aka react hook component), I am trying to call the function GetPhoto() in MarsData.js(aka the async function).
This code is then exported and used by another file that uses useState to display the API info on a webpage using REACT.
The date is not changing the API calls date, whats wrong?
//////////////////////////////////////////////////////////////
ChooseDate.js
import './ChooseDate.css'
import {useEffect, useState} from "react";
import GetPhoto from '../../APIs/MarsData';
function ChooseDate() {
const [data,setData] = useState(null)
const [print,setPrint] = useState(false)
function getDate(val){
//setPrint(false)
setData(val.target.value)
GetPhoto('2022-10-17')
console.log(val.target.value)
}
return(
<form action="/space-vision/public" method="get">
<div classname = "App">
{
print?
<h1>{data}</h1>
:null
}
<input type="text" onChange={getDate}/>
</div>
<button onClick={e=>{
e.preventDefault(),
setPrint(true)} }className='SearchButton'>Submit </button>
</form>)
}
export default ChooseDate;
////////////////////////////////////////////////////////////
MarsData.js
async function GetPhoto(val){
let path = '/mars-photos/api/v1/rovers/curiosity/photos?';
let earth_date= 'earth_date=2022-08-10&' //use format:'earth_date=[date]&'
let camera= '' //use format: camera=[string]&
let page = '' //use format: page=[int]&
let api_call=path + earth_date + camera + page;
if (val!=null)
earth_date='earth_date=2022-10-17&';
//'earth_date='+val.toString()+'&'
const APIKey = process.env.REACT_APP_API_KEY;
let response = await fetch('https://api.nasa.gov' + api_call + 'api_key=' + APIKey );
let data = await response.json();
console.log(data);
return data;
}
export default GetPhoto;
Your api_call variable is defined before you're checking if your val is null. If you assign your earth_date after the if statement it will update if val is not null.
if (val != null) earth_date = "earth_date=2022-10-17&";
let api_call = path + earth_date + camera + page;
If you want to use your val in the future you can wrap it in backticks
if (val != null) earth_date = `earth_date=${val}&`;
let api_call = path + earth_date + camera + page;
Hope this helps you with your project
Hey I was wondering if it is somehow possible to use a object literal in this case to clean up my switch statement.
export const getTravelInfo = () => {
const url = window.location.href;
switch (url as any) {
case url.includes('trips'):
return epicTrips;
case url.includes('mini-trips'):
return miniTrips;
case url.includes('sailing-trips'):
return sailingTrips;
default:
return epicTrips;
}
};
This is what I have so far, I am just not sure how or even if this is possible to pass in a function and loop over the url to determine what string is present in the url and then deliver that value to the user.
function getTravelInfo2 () {
const url = window.location.href;
var travel = {
'trips': epicTrips,
'mini-trips': miniTrips,
'sailing-trips': sailingTrips,
'default': epicTrips
};
return travel[url];
}
My solution was to First get what I need from the URL Via
const url = 'http://www.test.com/trips';
firstPart = url.split('/', -1)[-1];
getTravelInfo(firstPart);
const getTravelInfo = (type) => {
var travel = {
'trips': epicTrips,
'mini-trips': miniTrips,
'sailing-trips': sailingTrips,
'default': epicTrips
};
return (travel[type] || travel['default']);
}
Much cleaner and easier to execute and understand.
I have try this but I wasn't able to add a cookie or locale storage condition so it won't reload infinitely.
fetch('https://get.geojs.io/v1/ip/country')
.then(response => response.text())
.then(country_code => {
var domain_and_tld = window.location.host.split('.').splice(-2).join('.');
country_code = country_code.trim().toLowerCase();
switch (country_code) {
case 'us':
window.location.host = domain_and_tld;
break;
case 'gb':
window.location.host = `${domain_and_tld}?currency=GBP`;
break;
case 'fr':
window.location.host = `${domain_and_tld}?currency=EUR`;
break;
};
})
.catch(err => console.error(err));
Thanks for your help :)
It seems you want to change the query params based on the users country. We don't need to change window.location.host. You can change query params using window.location.search.
However, you only want to change window.location.search if it does not match your desired value (to avoid reloading infinitely). The solution below assumes currency is the only query param in your URL.
fetch('https://get.geojs.io/v1/ip/country')
.then(response => response.text())
.then(country_code => {
const country_code = country_code.trim().toLowerCase();
let desiredSearchParams = '';
switch (country_code) {
case 'gb':
desiredSearchParams = `?currency=GBP`;
break;
case 'fr':
desiredSearchParams = `?currency=EUR`;
break;
case 'us':
default:
break;
};
if(desiredSearchParams !== window.location.search) {
//change search param only if desired search param different from current search param
window.location.search = desiredSearchParams;
}
})
.catch(err => console.error(err));
This is quite a frustrating issue I am stuck on. I am exporting a parent function with quite a rigid structure for the purpose of library mocking.
const responses = require("../responses/index.js");
function fetch (
first = "contactsMultiple",
second = "passwordFail",
third = "contactsMultiple") {
this.first = first;
this.second = second;
this.third = third;
this.iteration = 1;
this.fetch = () => {
let body;
switch (this.iteration) {
case 1 :
body = responses.contacts[this.first];
break;
case 2 :
body = responses.password[this.second];
break;
case 3 :
body = responses.contacts[this.third];
break;
default:
body = responses.contacts["contactsMultiple"];
break;
}
const response = {
status: 200,
statusText: "OK",
json: () => {
return body;
}
};
this.iteration++;
return response;
}}
module.exports = fetch;
I export this, then import it, create a new instance of the function so I can set properties that I wish to increment and also set via the construction of the function. But the code then expects a function called fetch.
I need to be able to call it like:
const Fetch = new fetch();
then pass Fetch into the existing classes.
If I log this new function I can see it has a fetch property of a type function. but I keep getting this.fetch is not a function.
What am I missing?
Many thanks
Using React-router-component, i have set to load my home page with a component called gigist which is as folows:
var React = require('react');
var AppStore =require('../../stores/app-store.js');
var GigsListItem = require('./giglistitem.js');
var StoreWatchMixin =require('../../mixins/StoreWatchMixin.js');
function getGigs()
{
return {items:AppStore.getGigs()}
}
var GigsList= React.createClass({
mixins:[new StoreWatchMixin(getGigs)],
componentWillMount:function()
{
this.setState(getGigs());
console.log(this.state);
},
componentDidMount:function()
{
this.setState(getGigs());
console.log(this.state);
},
render:function()
{
console.log("rendered view");
var liststyle={border:'1px solid black'};
/*
var items=this.state.items.map(function(item)
{
return <GigsListItem gig={item} />
}) */
return (
<div className="row" style={liststyle}>
{this.state.items}
</div>
)
}
});
module.exports=GigsList;
I am making an ajax call using npm reqwest,but the problem is that the view is being rendered and setting its state to undefined before completion of ajax request.
You can see it from my console log
From the console '1' is at setting initial state for component giglist,'3' is component will mount,'rendered view' is while rendering component,'2' is for the ajax request
which clearly states that data is not being set to component state after the ajax call.
I need to set state for the component after i get response from it.
I tried setting state with componentwillmount and componentdidmount but neither solve my issue.
here is my store code:
var AppDispatcher = require('../dispatchers/app-dispatcher');
var AppConstants = require('../constants/app-constants');
var reqwest = require('reqwest');
var merge = require('react/lib/merge');
var EventEmitter = require('events').EventEmitter;
var CHANGE_EVENT = "change";
var _gigs = [];
function getGigsList()
{
reqwest({url:'myapi',
type:'get',
success:function(resp)
{
console.log(2);
return resp.gigs;
//alert(JSON.stringify(_gigs));
}.bind(this)})
}
var _cartItems = [];
function _removeItem(index){
_cartItems[index].inCart = false;
_cartItems.splice(index, 1);
}
function _increaseItem(index){
_cartItems[index].qty++;
}
function _decreaseItem(index){
if(_cartItems[index].qty>1){
_cartItems[index].qty--;
}
else {
_removeItem(index);
}
}
function _addItem(item){
if(!item.inCart){
item['qty'] = 1;
item['inCart'] = true;
_cartItems.push(item);
}
else {
_cartItems.forEach(function(cartItem, i){
if(cartItem.id===item.id){
_increaseItem(i);
}
});
}
}
function _CartTotals()
{
var qty=0,total=0;
_cartItems.forEach(function(cartItem)
{
qty+=cartItem.qty;
total+=cartItem.cost * cartItem.qty;
});
return {'qty':qty,'total':total}
}
var AppStore = merge(EventEmitter.prototype, {
emitChange:function(){
this.emit(CHANGE_EVENT)
},
addChangeListener:function(callback){
this.on(CHANGE_EVENT, callback)
},
removeChangeListener:function(callback){
this.removeListener(CHANGE_EVENT, callback)
},
getCart:function(){
return _cartItems
},
getGigs:function(){
alert(JSON.stringify(getGigsList()));
return getGigsList();
},
getCartTotals:function()
{
return _CartTotals();
},
dispatcherIndex:AppDispatcher.register(function(payload){
var action = payload.action; // this is our action from handleViewAction
switch(action.actionType){
case AppConstants.ADD_ITEM:
_addItem(payload.action.item);
break;
case AppConstants.REMOVE_ITEM:
_removeItem(payload.action.index);
break;
case AppConstants.INCREASE_ITEM:
_increaseItem(payload.action.index);
break;
case AppConstants.DECREASE_ITEM:
_decreaseItem(payload.action.index);
break;
}
AppStore.emitChange();
return true;
})
})
module.exports = AppStore;
can somebody point out where i am doing wrong.I hope i am clear.Thanks in advance
You cannot use return statements in asynchronous code, i.e, in the success callback of your ajax-call.
Instead, try to check if there are already gigs in the store, in which case you return them, and if there are no gigs in the store you do a request to get some and in the success callback you set the store state to the new data and emit a change that will tell your component to try to fetch the store state again.
function getGigsList()
{
if (_gigs.length > 0) { return _gigs; } //return immediately if data exists
reqwest({url:'myapi',
type:'get',
success:function(resp)
{
console.log(2);
_.gigs = resp.gigs;
this.emit(CHANGE_EVENT);
}.bind(this)})
return _gigs; //currently an empty array. this way you don't have to check for undefined in the component, you can just iterate over it directly
}