I keep trying to call an image location using stored data on firebase it seems to work fine on my other component, however, I keep getting this error on this component when switching to the page on my app, even the console logging of the data works fine. Any help would be great thanks!
export class Dog extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
};
}
componentDidMount = async () => {
await firebase
.database()
.ref("pets")
.on("value", snapshot => {
this.setState({ data: [].concat.apply([], snapshot.val()) });
});
};
render() {
return (
<View>
{this.state.data.map((obj, index) => {
console.log(obj.image);
return (
<View key={index}>
<Image source={require(obj.image)} />
</View>
);
})}
</View>
);
}
}
export default Dog;
Related
I'm trying to make a personal app and I'm running into some issues with the requests, nothing to do with the API.
The results of the request returns this JSON: https://pastebin.com/raw/vpdq2k6S
My code:
class Home extends Component {
componentDidMount() {
this.props.getTrending();
}
render() {
const { trending } = this.props.trending;
console.log(trending);
const Card = (props) => (
<Panel {...props} bordered header='Card title'>
{trending.results.map((i) => (
<React.Fragment key={i.id}>
<h6>{i.title}</h6>
</React.Fragment>
))}
</Panel>
);
return (
<div className='Home'>
<FlexboxGrid justify='center'>
<Card />
</FlexboxGrid>
</div>
);
}
}
export default connect(
(state) => {
return {
trending: state.trending,
};
},
{ getTrending }
)(Home);
My action:
import { GET_TRENDING } from "../types";
import axios from "axios";
export const getTrending = () => async (dispatch) => {
const res = await axios.get(
`https://api.themoviedb.org/3/movie/popular?api_key=KEY&language=en-US&page=1`
);
dispatch({
type: GET_TRENDING,
payload: res.data,
});
};
My reducer:
import { GET_TRENDING } from "../types";
const initialState = {
trending: [],
loading: true,
};
export default function trendingReducer(state = initialState, action) {
switch (action.type) {
case GET_TRENDING:
return {
...state,
trending: action.payload,
loading: false,
};
default:
return state;
}
}
Ignore the Card constant etc, that's related to an UI components library. You can see from the code that I'm logging the results of 'trending'. But I'm getting an empty array but here's the strange part:
If I change my map function from mapping through "trending.results" to "trending" and I refresh then the console returns an empty array and another array which is the correct one. If I change it back to "trending.results" then React auto-reloads the page returns me the correct array two times and it displays the data on the app but if I refresh the page without changing anything on the code then it goes back to showing an empty array and an error that says "cannot read property map of undefined" obviously cause somehow I'm not getting the correct data.
Anyone ever had this before? It makes absolutely no sense at all or if so then can someone guide me on how to solve this? I tried shutting down the React server completely and restarting it that wouldn't solve it. My brain is frozen (I can record a clip if required)
The answer is pretty simple. All you have to do is first getting the array from the api and then mapping through it. trending.results is not set so the error is shown. Cannot read property map of undefined
Go with a ternary operator:
{trending.results && trending.results.map((i) => (
<React.Fragment key={i.id}>
<h6>{i.title}</h6>
</React.Fragment>
))}
try this way.
export const getTrending = () => async (dispatch) => {
const res = await axios.get(
`https://api.themoviedb.org/3/movie/popular?api_key=KEY&language=en-US&page=1`
);
dispatch({
type: GET_TRENDING,
payload: res.data.results,
});
};
const Card = (props) => (
<Panel {...props} bordered header='Card title'>
{trending && trending.map((i) => (
<React.Fragment key={i.id}>
<h6>{i.title}</h6>
</React.Fragment>
))}
</Panel>
);
I need to use a different component depending on a propType, as a first attempt I'm using an object to store the components I need the problem is that It only works for the first key, for example it only works for AvatarList.Item, when I try to load Avatar.List it just doesn't load.
const component = {
AvatarList: {
Item: async () => (await import('../List/Avatar')).Avatar,
List: async () => (await import('../List/Avatar')).List,
},
Simple: {
List: async () => (await import('../List/Simple')).List,
Item: async () => (await import('../List/Simple')).Simple,
},
};
// Here there is the component and the default I componentType is "AvatarList"
class Articles extends Component {
renderListItem() {
const { componentType, newsArticles } = this.props;
const Item = importComponent(component[componentType].Item);
return newsArticles.map(({
url,
id,
imageUrl,
title,
description,
}) => (
<Item
id={id}
url={url}
imageUrl={imageUrl}
title={title}
description={description}
/>
));
}
renderList() {
const { componentType } = this.props;
const List = importComponent(component[componentType].List);
return (
<List>
{this.renderListItem()}
</List>
);
}
render() {
return (
this.renderList()
);
}
}
// This is the HOC I use for the loading the components with async/await
import React, { Component } from 'preact-compat';
import Loader from '../components/Loader/Loader';
export default function importComponent(importFunction) {
return class ComponentImporter extends Component {
async componentWillMount() {
this.setState({ component: await importFunction() });
}
render() {
const ImportedComponent = this.state.component;
return (
<Loader loaded={Boolean(this.state.component)}>
<ImportedComponent {...this.props} />
</Loader>
);
}
};
}
Apparently I can't get the named exports if they're coming from the same file dynamically, so the solution for this was just importing those files and get the variables on the componentDidMount.
In my application, I'm trying to fetch a data from my api. I've already tried to fetch data in my other modules and they're all working fine, but here it's not.
In here I'am trying to fetch a single object/data in my api.
Here's my code
Category.js
export default class Category extends Component {
constructor(props){
super(props)
this.state = {
data: [],
orderDet: '',
};
}
fetchDataOrderNo = async () => {
const response = await fetch("http://192.168.254.105:3308/OrderNo/order_no")
const json = await response.json()
this.setState({ orderDet: json })
}
componentDidMount() {
this.fetchDataOrderNo();
}
render() {
return (
<View>
<View style={{flexDirection: 'row'}}>
<Text>Table No: { this.state.orderDet }</Text>
</View>
</View>
)
}
}
You are getting an array as response to your request. You have to access the first object in the array, and get the order_no key:
fetchDataOrderNo = async () => {
const response = await fetch("http://192.168.254.105:3308/OrderNo/order_no")
const json = await response.json()
this.setState({ orderDet: json[0].order_no })
}
I'm new to React, I'm having trouble rendering my app due to this error. It's seems the data that I'm trying to render as elements won't render due to trying to set state when unmounted?
I'm not sure how I'm getting this error, as I'm setting the state of Data in componentDidMount.
How can I fix this issue?
error: attempted to update component that has already been unmounted (or failed to mount)
class Profile extends React.PureComponent {
static propTypes = {
navigation: PropTypes.object,
handleLogout: PropTypes.func,
user: PropTypes.object,
};
static navigationOptions = {
headerVisible: true,
title: 'Profile',
};
constructor(props) {
super(props);
this.state = {
data: [],
loading: true
};
}
componentDidMount() {
fetch("http://10.0.2.2:8080/combined", { method: 'get' })
.then(response => response.json())
.then(data => {
this.setState({data: data,});
})
.catch(function(err) {
//
})
}
render() {
const { user } = this.props;
let email;
if (user) {
email = user.rows[0].ACCTNO;
}
return (
<ContentWrapper>
<View style={styles.container}>
<Image style={styles.header} source={images.profileHeader} />
<View style={styles.body}>
<Avatar email={email} style={styles.avatar} />
{
this.state.data.map(function(rows, i){
this.setState({mounted: true});
return(
<View key={i}>
<Text>{rows.FIRSTNAME}</Text>
</View>
);
})
} <Text style={styles.email}>{_.capitalize(email)}</Text>
<Button
title="Log out"
icon={{ name: 'logout-variant', type: 'material-community' }}
onPress={this.logout}
style={styles.logoutButton}
/>
</View>
</View>
</ContentWrapper>
);
}
}
export default Profile;
In your render function, you're calling this.setState({mounted:true}). From React's component documentation:
The render() function should be pure, meaning that it does not modify component state, it returns the same result each time it's invoked, and it does not directly interact with the browser.
Here's the link to the React documentation on the render function.
There is another way this error can occur...thinking that props are individual arguments (props is actually a single argument)
import React from 'react';
const Posts = posts => { // WRONG
const Posts = ({posts}) => { // RIGHT
const renderPosts = () => {
return posts.map(post => <div>{post.title}</div>);
};
return <div>{renderPosts()}</div>;
};
My problem is I forget
import React from 'react'
in my .jsx file, since I thought importing React is not needed in functional component.
My problem was in Sider, Then inside Link tag I did misspell instead of /location I wrote /locaion .
<Menu.Item key="2">
<Icon type="settings" />
<span><Link style={styles.linkStyle} to="/locations">Locations</Link></span>
</Menu.Item>
I don't know if I forgot anything but .map is not returning the expected components.
This is my code:
data(){
var user = firebase.auth().currentUser;
var uid = user.uid;
axios.get('apilink here'+user.uid).then(function(response){
var arr = Object.values(response.data);
var listItems = arr.map(function(item){
return <Text>{item.name}</Text>
})
})
}
and this what I'm rendering:
render() {
return (
<Container style={{backgroundColor:'#F7F7F7'}}>
<Content>
{this.data}
</Content>
</Container>
)
}
}
You are approaching this in the wrong way. Your data function is not returning anything first of all so it won't display anything in your render method. You can debug that by simply calling your function and you will see that the value returned is undefined.
You are loading data from a remote resource, according to docs a good practice is to handle this in componentDidMount:
componentDidMount() is invoked immediately after a component is
mounted. Initialization that requires DOM nodes should go here. If you
need to load data from a remote endpoint, this is a good place to
instantiate the network request. Setting state in this method will
trigger a re-rendering.
So one way to approach this would be to move your data code into componentDidMount() and update the state of the component once the data has been retrieved. Something like this:
...
constructor(props) {
super(props);
this.state = { data: [] };
}
componentDidMount() {
var user = firebase.auth().currentUser;
var uid = user.uid;
axios.get('apilink here' + user.uid)
.then(function(response){
var arr = Object.values(response.data);
this.setState({ data: arr });
});
}
render() {
return (
<Container style={{backgroundColor:'#F7F7F7'}}>
<Content>
{
this.state.data
.map(function(item) {
return <Text>{item.name}</Text>
})
}
</Content>
</Container>
)
}
The problem is that you can't use your data() function directly in your render method because it's async.
You will need to work with a component state, which will be set after your API response.
Lets say this is your component:
export default class App extends React.Component {
constructor(props){
super(props)
this.state = {
data: null
}
this.getData()
}
getData = () => {
var user = firebase.auth().currentUser;
var uid = user.uid;
axios.get('apilink here'+user.uid).then(function(response){
var arr = Object.values(response.data);
var listItems = arr.map(function(item){
return <Text>{item.name}</Text>
})
this.setState({data: listItems})
})
}
render() {
return (
<Container style={{backgroundColor:'#F7F7F7'}}>
<Content>
{this.state.data}
</Content>
</Container>
);
}
}
This will let you load the state async response to your component