Object is invalid as react child while trying to use async function - javascript

I am trying to add translation system in my app. My sample code:
async translate(txt){
var res = await translate(txt, {
//some props
})
return res[0] //it was returned as an object, so taking the first element
}
render(){
return (
<View>
<Text>{this.translate('Hello')}</Text>
</View>
)
}
I know, async returns a promise but I could not figure out a way to use it in my case.
I have checked other questions, but those didn't work :(

You would need to wait for the promise to resolve before displaying the output of translate so you could use a state to store the output once translate finishes.
constructor() {
super();
this.state = {};
}
componentDidMount() {
this.translate("Hello").then((output) => this.setState({ text: output }));
}
render() {
return (
<View>
<Text>{this.state.text ? this.state.text : "Loading"}</Text>
</View>
);
}

Related

Pushing React component to javascript Array does not store actual return values

I am trying to push a React component into a javascript array. I am expecting the values in that array to be what the React component returns. Instead of that I get an array containing objects of like this: $$typeof: Symbol(react.element)....
Here is my code: loads books from an API when button is clicked and appends then to list of books already displayed (basically infinite scrolling):
Books:
function Books({ page }) {
const fetcher = url => api.get(url).then(response => response.data);
const { data: books } = useSWR(
`/books?page=${page}`,
fetcher
);
return books ? (
<>
{books.map(book => (
<Book key={book.id} book={book} />
))}
</>
) : null;
}
IndexPage:
class IndexPage extends React.Component {
constructor(props) {
super(props);
this.state = { pages: 1 };
}
load = () => {
this.setState({ pages: this.state.pages + 1 });
};
render() {
const books = [];
for (let page = 1; page <= this.state.pages; page++)
books.push(<Books page={page} key={page} />);
console.log(books) // logs `$$typeof: Symbol(react.element)...` instead of `[null]`.
return (
<>
{books.length ? (
books
) : (
// This never executes because `books.length` is never zero
<li>No books yet.</li>
)}
<button onClick={this.load}>Load More Books</button>
</>
);
}
}
My goal is to find a way to display <li>No books yet.</li> in the code below but I cannot find a way to do it dealing with the values I find in the array. Right now, if there are no objects I just see a blank page.
How can I make sure that the React component actual return values are stored in my array instead of these "symbol" objects?
You always want to set your default state in the constructor in ReactJS. Take a look at the official documentation...
Add a class constructor that assigns the initial this.state:
constructor(props) {
super(props);
this.state = {date: new Date()};
}
Source: ReactJS.org: State and Lifecycle / Adding Local State to a Class
If you're using an API, you can update the state once the fetch() or ajax() requests finally resolve, and fill the state with useful data. Since you want to show "no books yet" when there's nothing loaded yet, indicate this in the state; remove pages:1 (as there are no pages) and set pages:0...
constructor(props) {
super(props);
this.state = { pages: 0 };
}
Then your statement should work and show correctly, as the condition for showing it is now true: books.length ?. Of course, you may want to get even more fancy, and indicate the difference between loading and nothing found. For instance...
constructor(props) {
super(props);
this.state = { pages: 0, loaded: false };
}
And in your render() call...
render() {
if(!this.state.loaded) {
return (<span> loading api </span>);
}
return (
{books.length ? (
books
) : (
// This never executes because `books.length` is never zero
<li>No books yet.</li>
)}
)
}
Then later in your code, once your API has done its loading...
this.setState({pages: somepagenumber, loaded: true});

Why I cant set value to my states? REAECT-NATIVE

im new in react-native, im passing data by navigation to my edit_note screen, once i received i set it to my states, but it doesnt work, if i print them, it shows their values, but setting to my states doesnt work, heres the code:
heres the Notes class, in the navigation function im passing the datas, data and note_number to Edit_note
render() {
return (
<>
<View style = {this.styles.View}>
<FlatList data = {this.props.data} renderItem = {({item}) => (<TouchableOpacity onPress = {() => this.props.navigation.navigate("Edit_note", {data: this.props.data, note_number: item.note_number})}><Text style = {this.styles.Text}>{item.title}</Text></TouchableOpacity>)} keyExtractor = {(item) => item.note_number.toString()}></FlatList>
</View>
</>
);
}
in Edit_note im receiving it like this:
class Edit_note extends Component {
constructor() {
super();
this.state = {
array_notes: [],
note_number: "",
}
}
componentDidMount() {
const {params} = this.props.navigation.state;
let x = params.note_number;
this.setState({note_number: x});
console.log(this.state.note_number);
}
render() {
return (
<Text></Text>
);
}
}
if i print x, it will print the note_number, but setting it into note_number, and print it, it doesnt show anything, why?
You actually set it but your console.log() fires before the change.
After a state changes component rerenders so you can try printing it on screen like;
render() {
return (
<Text>{this.state.note_number}</Text>
);
}
setState is asynchronous that means that the state indeed changes but the console.log right after the setState is not showing the change.
You can learn more about it here.

A function containing an another async function is not returning to the main function

I've a function renderMe() that waits for an another function async fetchingTransactions() to return that in turn will be returned to the main render function. Unfortunately, async fetchintransactions is returning an array but it couldn't be utilized to be returned by renderMe().
What I'm trying to do is, because its a async fetchingtransactions is an async function, I tried to use await fetchingtransactions and .then to get the array but the main render function says that I'm returning an object which cannot be rendered.
async fetchingTransactions(){
return '10'
}
renderMe(){
this.fetchingtransactions().then((val) => {
return(
<View>
<Text>Number is {val}</Text>
</View>
)
})
}
render(){
return(
<View>
{this.renderMe()}
</View>
)
}
I expect the result to be a view having a text: "Number is 10". It's just an example and I'll be using real await fetch function in the async function but the following code is the basis of it.
renderMe() has no return statement, so it returns undefined
You could return the promise, but then this.renderMe() would give you a promise and not the <View> element
Render data, in the component, from the component's state.
render(){
if (this.state.val !== undefined) {
return(
<View>
<View>
<Text>Number is {this.state.val}</Text>
</View>
</View>
);
} else {
return something else;
}
}
Call fetchingtransactions and then update the state.

Cannot set a global variable equal to a value returned from a Promise

I'm attempting to set a global variable equal to a JSON element being returned from a Promise with Axios, within my React Native application. I've followed the advice from this question, but still am unable to set the variable's value.
Here is my method using an Axios call:
temp_high = null;
_getForecast(zipcode)
{
const request = "http://api.wunderground.com/api/" + API_KEY + "/forecast/q/" + zipcode + ".json";
return axios.get(request).then( (response) => {
if(response.status == 200) {
this.response = response.data;
return this.response;
}
});
}
And my render:
render() {
this._getForecast(49306).then(data => {
this.temp_high = parseInt(data.forecast.simpleforecast.forecastday[0].high.fahrenheit);
});
return (
<View style={styles.container}>
<Text>Weather for Belmont, MI</Text>
<Text>High: {this.temp_high}</Text>
<Text></Text>
</View>
);
}
}
If I log data.forecast.simpleforecast.forecastday[0].high.fahrenheit to the console, or create an alert calling that, the value is indeed correct. I just cannot seem to set it equal to temp_high.
If you want your component's view to update in response to the new data, you need to use setState, to tell React to re-render. React doesn't react (hue) to regular class properties.
Async functions shouldn't be called from render. You should instead use lifecycle hooks, and componentDidMount would work best for this situation, to fetch the information once on mount.
With that in mind, you'd end up with something like this:
class Example extends React.Component {
state = {
data: null
}
componentDidMount() {
// fetch forecast data when the component mounts
this._getForecast(49306)
}
_getForecast(zipcode) {
const request =
"http://api.wunderground.com/api/" +
API_KEY +
"/forecast/q/" +
zipcode +
".json"
return axios.get(request).then(response => {
if (response.status == 200) {
this.setState({ data: response.data })
}
})
}
render() {
if (this.state.data === null) {
// don't render if we haven't received data yet
// otherwise we'll get an error trying to calculate temp_high
return
}
const temp_high = Number(
this.state.data.forecast.simpleforecast.forecastday[0].high.fahrenheit
)
return (
<View style={styles.container}>
<Text>Weather for Belmont, MI</Text>
<Text>High: {temp_high}</Text>
<Text />
</View>
)
}
}
If you want to assign to a standalone variable (even if it happens to be in the global scope), don't prefix it with this. Just
temp_high = Number(data.forecast.simpleforecast.forecastday[0].high.fahrenheit);
this resolves to the calling context of the current function you're in.
This answer is wrong, the arrow allows for https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) be carefull with the keyword "this".
It is currently setting the this.temp_high to the _getForecast function. What you might want to do is have
render() {
var self = this;
this._getForecast(49306).then(data => {
self.temp_high
=parseInt(data.forecast.simpleforecast.forecastday[0].high.fahrenheit);
});
return (
<View style={styles.container}>
<Text>Weather for Belmont, MI</Text>
<Text>High: {this.temp_high}</Text>
<Text></Text>
</View>
);
}
}

Load fetch into a variable React Native

Learning JavaScript and React Native and I seem to not be understanding how to put a json response into a variable I can access. I have looked at this, this, this and also the Mozilla documentation and also this and a lot more but still don't seem to grasp the concept or get it to work.
export default class AwesomeApp extends Component {
constructor(props) {
super(props);
this.state = { questions: [] };
}
componentWillMount() {
this.getQuestionsFromAPI().then((res) => {
this.setState({
questions: res
});
});
let url = 'http://127.0.0.1:3000/trivia';
async function getQuestionsFromAPI() {
fetch(url).then(response => response.json())
.then(function(json) {
questions = json;
//console.log(questions[0]);
return questions;})
.catch(error => console.log(error));
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.question}>
{ this.props.questions[0] }
</Text>
<View style={{ flex: 1, padding: 20 }}>
<CheckBox
label={ this.props.questions }
checked={false}
onChange={(checked) => console.log('I am checked', checked)}
/>
</View>
AppRegistry.registerComponent('AwesomeApp', () => AwesomeApp);
I get the error "undefined is not a function (evaluating 'this.getQuestionsFromAPI()'). Looking at it in a browser, setting:
var quests = getQuestionsFromAPI()
returns a promise
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: undefined}
while
console.log(questions[0]);
returns an object which is what I want. What am I not understanding?
There are a few issues in the code sample you sent above.
Firstly, if you indent your code properly you will notice that the function getQuestionsFromAPI is declared within componentWillMount. Meaning that when you refer to it using this it is not found.
Secondly, getQuestionsFromAPI does not return a promise. You should return fetch(...).
Finally, you are trying to get the questions using this.props.questions, but you are assigning the questions in the state, so you should be using this.state.questions instead.

Categories