I am trying to render a list which calls a function to render the rows, but how can I pass the paramater data to the function/handler?
The data is in json style.
I tried many things but I always get an error back, what am I doing wrong?
This the code:
componentDidMount() {
fetch('http://link/json.php', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
dataJson = responseJson;
this.setState({
preLoad: true
});
})
.catch((error) => {
});
}
renderRows(item){
if(item.type == 2){
return(
<ListItem>
<Thumbnail square size={80} source={{ uri: 'item.image' }} />
<Body>
<Text>{item.title}</Text>
<Text note>{item.desc}</Text>
</Body>
</ListItem>
)
}
}
renderMenu(){
if(this.state.preLoad){
return(
<List dataArray={dataJson}
renderRow={(item) =>
this.renderRows().bind(this,item)
}>
</List>
)
}else{
return(
<Body>{shimmerRows}</Body>
)
}
}
render() {
return (
<Container style={styles.container}>
{this.renderMenu()}
</Container>
);
}
It seems you just need to save your response to the state.
this.setState({
preLoad: true,
dataJson: responseJson,
});
And do the binding correctly.
<List dataArray={this.state.dataJson}
renderRow={(item) => this.renderRows.bind(this,item)}>
</List>
Related
I am working in ReactJS and I have a database on Firebase called posts as a collection of objects. I am trying to iterate through the database objects and return a component with each assigned with one of the unique keys that firebase creates for the objects as props.
As a result example of what I am trying to achieve:
<Post
key={-MQcz3BC4lbKnvFe8Jl}
title={post.title}
type={post.type}
body={post.body}
clicked={() => this.postAnswerHandler( post.id )}
/>
<Post
key={-MQxVra23HwWb8ogRJZ}
title={post.title}
type={post.type}
body={post.body}
clicked={() => this.postAnswerHandler( post.id )}
/>
...and so on. Can anyone help with iterating through the firebase Data and assigning the keys to my React components?
Here is the current code I am using for this:
class Posts extends Component {
state = {
posts: []
}
componentDidMount () {
axios.get( 'https://blog-6d4da-default-rtdb.firebaseio.com/posts.json' )
.then( response => {
let posts = Object.values(response.data);
let key = Object.keys(response.data);
const updatedPosts = posts.map( post => {
return {
...post,
}
} );
this.setState( { posts: updatedPosts } );
} )
.catch( error => {
console.log( error );
// this.setState({error: true});
} );
}
render () {
let posts = <p style={{ textAlign: 'center' }}>Something went wrong!</p>;
if ( !this.state.error ) {
posts = this.state.posts.map( (post) => {
return (
<Post
key={post.key}
title={post.title}
type={post.type}
body={post.body}
clicked={() => this.postAnswerHandler( post.id )}
/>
// </Link>
);
} );
}
I think you're looking for:
let keys = Object.keys(response.data);
const updatedPosts = keys.map( key => {
return {
key, ...response.data[key],
}
} );
this.setState( { posts: updatedPosts } );
Use Object.entries()
axios.get( 'https://blog-6d4da-default-rtdb.firebaseio.com/posts.json' )
.then( response => {
this.setState( { posts: response } );
} )
render () {
let posts = <p style={{ textAlign: 'center' }}>Something went wrong!</p>;
if ( !this.state.error ) {
posts = Object.entries(this.state.posts).map( ([post, key]) => {
return (
<Post
key={key}
title={post.title}
type={post.type}
body={post.body}
clicked={() => this.postAnswerHandler( post.id )}
/>
// </Link>
);
} );
}
I am trying to fetch data from external api and show that on display. When I press button it calls function which console things normally but can't show returned value.
export default function HomeScreen() {
return (
<View style={styles.container}>
<Button title='show data' onPress={loadText}/>
<Text>{loadText}</Text>
</View>
);
function loadText(){
fetch('http://192.168.88.253:5000/read')
.then((response) => response.json())
.then((responseJson) => {
return (
console.log(responseJson.city)
);
})
.catch((error) => {
console.error(error);
});
}
}
If I understand it, loadText function must return responseJson.city value as a string.
How can I show it in <View> or <Text>?
export default function HomeScreen() {
constructor(props){
super(props);
this.state = {
city: ''
}
}
return (
<View style={styles.container}>
<Button title='show data' onPress={() => this.loadText()}/>
<Text>{this.state.city}</Text>
</View>
);
loadText(){
fetch('http://192.168.88.253:5000/read')
.then((response) => response.json())
.then((responseJson) => {
this.setState({city: responseJson.city});
})
.catch((error) => {
console.error(error);
});
}
}
you can use alert() to display the data.
alert is the popup which will be displayed on the mobile screen.
export default function HomeScreen() {
return (
<View style={styles.container}>
<Button title='show data' onPress={loadText}/>
<Text>{loadText}</Text>
</View>
);
function loadText(){
fetch('http://192.168.88.253:5000/read')
.then((response) => response.json())
.then((responseJson) => {
return (
alert(JSON.stringfy(responseJson.city))
);
})
.catch((error) => {
alert(JSON.stringfy(error));
});
}
}
My React Native app fetch API data and I need to print the first index of response but it's not, and gets all of the "ozone" for example in all child of the parent Array and when I print val[0] when Mapping I have nothing printed
My Code|
export default class App extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, dataSource: null };
}
async componentDidMount() {
let API_WEATHER =
"https://api.weatherbit.io/v2.0/forecast/daily?city=Raleigh,NC&key={API_KEY}";
fetch(API_WEATHER)
.then(response => response.json())
.then(responseJson => {
console.log(responseJson.data);
this.setState({
isLoading: false,
dataSource: responseJson.data
});
})
.catch(error => {
console.log(error);
});
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator size="large" />
</View>
);
}
let weather= this.state.dataSource.map((val, key) => {
return (
<Text key={key}>
{val.ozone}
</Text>
);
});
return (
<ScrollView style={styles.container}>
<ScrollView>
<View>
<Text>{weather}</Text>
</View>
</ScrollView>
</ScrollView>
);
}
In this part of the code when i log the respone JSON obj
.then(responseJson => {
console.log(responseJson.data);
console.log(responseJson.data[0]);
console.log(responseJson.data[0].datetime);
}
i have what i need, but when print them in View i have Erroe
look at the Images
You're probably the first key of the object.
obj[Object.keys(obj)[0]];
Also, you can use
Try the for … in loop and break after the first iteration
for (var prop in object) {
// object[prop]
break;
}
I'm trying to make a game with react native and I want to show a different options when i change the picker value.
basically when I select the first option on the picker a component has to appear and when I select the second one another component.
I tried this function but not working
pickerOptionText = () => {
if (this.state.PickerValueHolder==this.state.filter[0]) {
return (
<Text>{instructions[2]}</Text>
);
}else {
return (
<Text>{instructions[1]}</Text>
);
}
return null;
}
here is my code
export default class Facil extends Component {
constructor(props)
{
super(props);
this.state = {
isLoading: true,
PickerValueHolder : '',
filter: [
{
"option":"Palabras por categoria"
},
{
"option":"Palabras por caracteres"
}
],
dataSource:[]
}
}
componentDidMount() {
return fetch(API_URL)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson
})
})
.catch((error) => {
console.error(error);
});
}
render() {
const resizeMode = 'stretch';
pickerOptionText = () => {
if (this.state.PickerValueHolder==this.state.filter[0]) {
return (
<Text>{instructions[2]}</Text>
);
}else {
return (
<Text>{instructions[1]}</Text>
);
}
return null;
}
return (
<View style={styles.container}>
<Image source={require('../../Images/HomeLayout.png')}
style={styles.imagen}
/>
<View style={styles.mView}>
<View style={styles.panel}>
<Text style={styles.titlePanel}>MODO FACIL</Text>
<Text style={styles.instructions}>{instructions[0]}</Text>
<View style={styles.picker}>
<Picker
selectedValue={this.state.PickerValueHolder}
style={ {height: '100%',width: '100%'}}
mode="dropdown"
onValueChange={(itemValue, itemIndex) => this.setState({PickerValueHolder: itemValue})} >
{ this.state.filter.map((item, key)=>(
<Picker.Item label={item.option} value={item.option} key={key} />)
)}
</Picker>
</View>
<View style={styles.gameOpt}>
<Text>[dynamic options]</Text>
{pickerOptionText}
</View>
</View>
</View>
<TouchableOpacity style={styles.button}><Text style={styles.btnText}>Play!</Text></TouchableOpacity>
</View>
);
}
}
You forgot '()'.
pickerOptionText is a function, not a React component.
<Text>[dynamic options]</Text>
{pickerOptionText}
to:
<Text>[dynamic options]</Text>
{pickerOptionText()}
You can try using Conditional Rendering of JSX, by this you can use ternary operator and a simple if condition. this is written as:
{this.state.PickerValueHolder==this.state.filter[0] ?
<Text>{instructions[2]}</Text>
:<Text>{instructions[1]}</Text>
}
and if you need simple if condition then,
{ condition == true && <Text>your text here</Text>
}
First of all, I want to explain what I want to do and after where my problem is.
Initially I do a fetch request to load some data, since here is working okey.
After with one value of this data I want to do another fetch. For that I call another function renderImage(), where I do the fetch and I render the code that I want.
My problem is that is not rendering nothing, because is not changing the status into loaded. And of course fetch is asynchronous and needs more time.
And I don't know how do it that it works and more simple because I thinks that I doing it a little bit complicated.
This is my code:
class Dashboard extends Component{
constructor(props){
super(props)
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
}),
loaded: false,
datos: '',
}
}
componentDidMount(){
this.fetchData();
}
fetchData(){
fetch(REQUEST_URL)
.then((response) => response.json())
.then ((responseData) =>{
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData),
})
})
}
renderLoadingView(){
return(
<View>
<Text>Cargando...</Text>
</View>
)
}
async renderImage(receta){
const REQUEST_URL = "yyyyyyyy" + receta.user_id;
const response = await fetch(REQUEST_URL);
const json = await response.json();
this.setState({ loaded : true});
return(
<Card >
<CardItem>
<Left>
<TouchableOpacity>
<Thumbnail style={{width: 50, height: 50, borderRadius: 25}} source={{uri: json.imageUrl}} />
</TouchableOpacity>
<Body>
<Text>{receta.Titulo}</Text>
<Text>{receta.Username}</Text>
</Body>
</Left>
</CardItem>
</Card>
)
}
renderReceta(receta){
return this.renderImage(receta);
}
render(){
if(!this.state.loaded){
return this.renderLoadingView();
}
else{
return(
<Container>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderReceta.bind(this)}
/>
</Container>
)
}
}
}
Perhaps not an "answer" but the question is a bit vague. This can be solved in many ways.
Option one:
Load the array first, then show the list, and async "sideload" each row's images.
Can be bad if you have a lot of images so watch out for that. Also you might load images here that you might never render (they are out of view, e.g. the user never scrolls to them), but you also wont load them twice to... pros and cons.
class Dashboard extends Component{
constructor(props){
super(props)
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
}),
loaded: false,
datos: '',
images: {
}
}
}
componentDidMount(){
this.fetchData();
}
fetchData(){
fetch(REQUEST_URL)
.then((response) => response.json())
.then ((responseData) =>{
this.setState({
loaded: true,
dataSource: this.state.dataSource.cloneWithRows(responseData),
});
this.fetchImageUrls(responseData);
});
}
fetchImageUrls(responseData){ //assuming respons data is an array of receta objects
responseData.forEach(({user_id})=>{
fetch("wwwsomewhere").then(r => r.json()).then(({imageUrl})=>{
this.setState({
images: Object.assign(this.state.images, {
[user_id]: imageUrl
})
});
});
});
}
renderLoadingView(){
return(
<View>
<Text>Cargando...</Text>
</View>
)
}
renderImage(receta){
const {Titulo, Username, user_id} = receta;
return(
<Card >
<CardItem>
<Left>
<TouchableOpacity>
{this.state.images[user_id] ?
<Thumbnail style={{width: 50, height: 50, borderRadius: 25}} source={{uri: this.state.images[user_id]}} />
: "Loading (load thumb here?)"
}
</TouchableOpacity>
<Body>
<Text>{receta.Titulo}</Text>
<Text>{receta.Username}</Text>
</Body>
</Left>
</CardItem>
</Card>
)
}
renderReceta(receta){
return this.renderImage(receta);
}
render(){
if(!this.state.loaded){
return this.renderLoadingView();
}
else{
return(
<Container>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderReceta.bind(this)}
/>
</Container>
)
}
}
}
Options 2:
Bundle upp all your loading into one and after resolve rerender.
class Dashboard extends Component{
constructor(props){
super(props)
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
}),
loaded: false,
datos: '',
recetas: {
}
}
}
componentDidMount(){
this.fetchData();
}
fetchData(){
fetch(REQUEST_URL)
.then((response) => response.json())
.then ((responseData) =>{
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData),
});
this.fetchImageUrls(responseData);
});
}
fetchImageUrls(responseData){ //assuming respons data is an array of receta objects
//Load all images
Promise.all(responseData.map(({user_id})=>{
return fetch("wwwsomewhere").then(r => r.json());
})).then((recetasArray)=>{
//When all thumb objects (Recetas) have been resolved
//map over the receta object array and create a hash (so you can access them by id later)
this.setState({
loaded: true,
recetas: recetasArray.reduce((acc, receta)=>{
acc[recept.user_id] = receta;
return acc;
},{})
});
});
}
renderLoadingView(){
return(
<View>
<Text>Cargando...</Text>
</View>
)
}
renderImage(receta){
const {Titulo, Username, user_id} = receta;
return(
<Card >
<CardItem>
<Left>
<TouchableOpacity>
<Thumbnail style={{width: 50, height: 50, borderRadius: 25}} source={{uri: this.state.recetas[user_id]}} />
</TouchableOpacity>
<Body>
<Text>{receta.Titulo}</Text>
<Text>{receta.Username}</Text>
</Body>
</Left>
</CardItem>
</Card>
)
}
renderReceta(receta){
return this.renderImage(receta);
}
render(){
if(!this.state.loaded){
return this.renderLoadingView();
}
else{
return(
<Container>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderReceta.bind(this)}
/>
</Container>
)
}
}
}
Untested code but just wanted to share my ideas.