I have been building a basic weather app using React, Redux, Redux-promise and Axios (handling an API for the current weather using openweathermap.org).
If the button gets clicked, the weather parameters of the city (Cecciola) should be displayed on the console.
The Action correctly retrieves the data and, thanks to Promise, it is passed onto the reducer as a normal payload.data, not a promise.
Then, the container responsible for the rendering of the city.name is connected to the reducer managing the weather (so that you can access it using this.props) but, if the button is clicked, the console.log(this.props.tempo....) says that the object is undefined. Why?
GitHub Repo link
Trying your repo, logging to the console this.props.tempo works just fine for me in the render method of ceciola component.
Where I see the error, is in your renderR() function. You're attempting to use diocane.city.name but there is no 'city' property for that object.
Try: <p>{diocane.name}</p> to get the name.
_______ UPDATE ________
Response to your comment: I pulled the latest version from the repo, and again, everything seems to work just fine when you click the button to retrieve the data. As the code is now, you are doing:
console.log(this.props.tempo[0])
So, on first load of the component, you have nothing in the props.tempo array, so you see undefined in the console. When you click the button, you now have a single object in the array and that log statement works just fine.
I changed your render() method to:
render() {
if (this.props.tempo.length > 0) {
console.log("TEMPO", this.props.tempo[0])
console.log("ID", this.props.tempo[0].id)
}
return (
<div>
{this.props.tempo.map(t => {
return <div key={t.id}>{t.name}: {t.main.temp} </div>
})}
</div>
);
}
And it logs out the expected information. You just need to confirm that the tempo prop has something in the array before attempting to access it. And then, when you do, make sure you're accessing the individual object(s) inside. I show an example of this in the return() method above: using map to iterate and return a new array of <div> elements with the tempo object info.
Related
I am learning about Hooks, React Context, and other things, but I feel that I don't understand how DevTools work. My axios call returns some data which updates the state. I can see the state change and my console.log displays the information.
This is state under Hooks:
This is what the console.log(todos) spits out:
This is how console log looks expanded:
I don't know if the todos have the form of {[{_id, title, userId}]} or [{_id, title, userId}] under DevTools.
I think it is the latter and tried to access via console.log(todos[0]), console.log(todos[0]['title']), etc but those return undefined yet console.log(todos) doesn't. Is there a reason why this is so?
If console.log(todos) logs this object {todos:[...]} it means that the todos object contains a todos property that contains the array. That is probably confusing you since you need to select todos once again:
console.log(todos.todos)
(The full selector will then be console.log(todos.todos[0]['title']) )
My guess is that you saved the complete Redux state into a todos variable in your code via var todos = state;.
I suggest you save the state in another variable name instead to avoid the confusion:
var reduxState = state;
...or save only the todos state:
var reduxTodosState = state.todos;
I'm a beginner both in programming and React and I have to create a functioning google Map single page website. I'm using google-map-react.
I have a parent App.js (containing the call to and a HTML sidebar) and a child Map.js containing the map itself and axios request function.
I'm making axios requests to fetch data from foursquare api. It works without side effects. Then I want to pass those data to my app.js and update the parent state so that I can renderthe locations on the sidebar.
This is the function I used (in Map.js). I had to put the call in componentWillReceiveProps as a last resource because componentDidMount didn't work:
https://jsfiddle.net/kd1yuhe5/
I think this may be the issue, but it's also the only way I found to make the list show:
this.props.updateVenues(this.state.venues)
This is the code from App.js
updateVenues(venues) {
this.setState({
venues: venues,
});
}
Then I called the method like this:
<Map updateVenues={this.updateVenues.bind(this)} />
The code works, venues are shown in the sidebar (if you need the code let me know, but I don't think it's relevant), but the I keep making requests until I exceed quota.
Again: I'm a beginner. I just started 3 months ago.
EDIT:
Here are both components:
Map.js
https://jsfiddle.net/kd1yuhe5/5/
App.js
https://jsfiddle.net/xwzrm4bp/2/
When the state of a React component is updated (and without custom implementation of componentShouldUpdate), it triggers a re render of that component (ie call the render function).
If the props of the children of this component have changed since the last render, they will also re render.
They re render because they have received new props, and this will also call their componentWillReceiveProps function.
Since you are fetching data each time Map will receive props, you are fetching data each time something change (state change) on App.
First in Map.js, this.props.query is assigned to this.state.query.
This looks like an error, as in this case what you want are the new props receceived by componentWillReceiveProps, this is the first argument of this function.
So you should assign props.query to this.state.query instead.
Except that actually you should not:
this.state.query is only used in componentWillReceiveProps, therefore there is no need to put props.query into state.query.
Second since you have both this.props.query from the previous props update and props.query which is the new received query, you have the opportunity to fetch only when the query has actually changed:
// Receive the update query from parent and fetch the data
componentWillReceiveProps(nextProps){
if (this.props.query !== nextProps.query) {
this.fetchData(nextProps.query);
}
}
Now you may ask, "ok but why my Map component was always re rendered, even when its props didn't changed".
But they did:
in App.js
<Map
query={this.state.query}
center={this.state.center}
updateVenues={this.updateVenues.bind(this)}
getClickedMarker={this.getClickedMarker.bind(this)}
/>
By calling this.updateVenues.bind(this) and this.getClickedMarker.bind(this) in the render method, you are creating new values (actually new Function references)for the updateVenues and getClickedMarker props, at each render.
Instead, you should bind these method in the contructor of App:
constructor(props) {
super(props);
this.updateVenues = this.updateVenues.bind(this);
this.getClickedMarker = this.getClickedMarker.bind(this);
....
}
....
<Map
query={this.state.query}
center={this.state.center}
updateVenues={this.updateVenues}
getClickedMarker={this.getClickedMarker}
/>
This may limit your API calls a lot, you may also debounce them.
The basic problem I'm having is that I'm updating my data using an AJAX request and then setting the state of data, but in the view, the data never update even though my state is updated. I've figured out that it's because the key is the same (which it should be because I'm just using the ID mongoose provides).
If I do things like set the state to nothing and then set then set the new data then it updates. Or if I set the key to a randomly generated key it also works, but both of these don't feel right. I want to know what the correct way to re-render an updated object when using the map function.
It looks something like this:
Object.keys(this.state.data).map((i) => (
<MyComponent key={ this.state.data[i]._id }
))
And then I have a basic AJAX request that does this.setState({ data: response.data }).
How do I make react update the data in the view for the updated item properly?
Can you add the index as a prefix to the _id?
key={ `${i}_${this.state.data[i]._id}`}
I am not really sure it is related to the key, if you console.log(this.state.data) just before your code it gets updated when it should? it seems to me that the props are not getting passed to the component.
I mean I often use the index of map in the key in the lists I never had any problem with that.
I want to map a state, but that state (the name of the state is "task", it is the child of parent state called "timesheet", the "timesheet" state is already defined using componentWillMount) is still undefined UNTIL an action creator has been triggered (click a button) inside my page. But, i already define timesheet.task.map inside jsx, and thus the page cannot load and it shows an error "cannot read property map of undefined".
code
So as you can see here, i want to map a list of 'select' options from a state which is called when an event is triggered (it is still undefined when the page renders), but the page will not load because the timesheet.task is still undefined when the page load the first time
Do you have any idea how to fix this? I was thinking to initialize the state, but i don't know how to do it.Thank you very much!
Very common situation. At the top of your render() - just add a conditional to check if that value is valid or not.. something like:
if (!this.state.timesheet.task) {
return <p> waiting for my value </p> // add any generic component to here that would await your value
}
Depending on your page layout, you might want to just create a small component to inject as a conditional as you await your value to be populated.
I am having a problem rendering the props value in react.
I have added data fetched from an API to a redux store, and then mapped the state to my App component. The data shows up in my props when I view the component using react dev tools, and I can access the value of the API prop through the console by typing:
$r.props.products.items[0].title
Here's an image of Chrome dev tools illustrating ability to access props from App component for reference:
But when I try to render the props in the App component using
{this.props.products.items[0].title}
The component breaks and I receive an error in the console
saying:
Uncaught TypeError: Cannot read property 'title' of undefined
If it helps, I've created a gist here showing my App.js component where the state is mapped to the props, the actions and reducers for the redux store.
If anyone can help me that would be great. I've been pulling my hair out over it all day.
Reason is, you are fetching the data from api, until you didn't get the response {this.props.products.item} will be undefined, because render will get executed before you get the response. So either you need to hold the rendering by using some bool until you didn't get the response or put the check, like this:
{this.props.products.items && this.props.products.items[0].title}
If the previous answer is not working, the only thing I can think of is that items may exist as an empty array, in the form of this.props.products.items = []
Try:
{
this.props.products.items &&
this.props.products.items.length > 0 &&
this.props.products.items[0].title
}