Trying to fetch data from and external API but code breaks - reactjs

I'm trying to fetch data from an external API. It shows at first but when I refreshes the browser, it goes blank. The code is in my GitHub repo. thanks
https://github.com/Rengkat/weather-app.git

The initial state of data is {}. As a consequence, data.name and data.sys are undefined, so trying to render data.sys.country throws an error before the app can render the input field.
<div className="details">
<div className="country">
<h3>
{data.name}, {data.sys.country}
</h3>
I recommend setting the initial state of data to null and wrapping everything other than the input field in a conditional that only allows rendering if data is truthy:
function FetchDataComponent() {
const [data, setData] = useState(null);
...
return (
<div className="container">
<div className="input">
<input
type="text"
placeholder="Enter country..."
value={country}
onChange={handleChange}
onKeyPress={fetchData}
/>
</div>
{data ? (
<div className="details">
<div className="country">
<h3>
{data.name}, {data.sys.country}
</h3>
</div>
...

Related

Is there any way to sort the data from database by time, i mean the latest data first?

I'm currently using the map function which is iterating in the first come basis but i want to show the latest data first. Consider the messages data from the code below. I want to put the latest messages first. Can someone help me with this?
Thanks in advance...
<ul>
{
messages.reverse().map(message => (
<section>
<li key={message._id}>
<div className='post-container'>
<div className='user-profile'>
<div>
<p className='small'>{message.user.username}</p>
<span>posted/modified at: {message.createdAt}</span>
</div>
</div>
<p className='post-text'>{message.text}</p><br />
<div>
<div>
<h5>{message.likes.length} Likes </h5>
{!message.likes.includes(userdata._id)
?
<button className='likebtn' onClick={()=>{likePost(message._id)}}><FcLikePlaceholder /> Like</button>
:
<button className='likebtn' onClick={()=>{unlikePost(message._id)}}><FcLike /> Unlike</button>
}
<h5>Comments:</h5>
{
message.comments.map(com=>{
return (
<div className='comments'><p><label>{com.postedBy.username}: </label>{com.comment}</p></div>
)
})
}
</div>
<form onSubmit={(e)=>{
e.preventDefault()
makeComment(e.target[0].value, message._id)
}}>
<input type='text' placeholder='Add a comment...'></input>
</form>
</div>
</div>
</li><br />
</section>
))
}
</ul>
I'm currently using the map function which is iterating in the first come basis but i want to show the latest data first. Can someone help me with this?
Thanks in advance...
You can use sorting function before mapping like this:
messages.sort((a,b) => b.date - a.date).map(message => {});

React pagination component

Its a movie search/finder, with pagination component.
The pagination currently doesn't work as aspected.
issue: clicking the pagination the movies are always the same.
Sorry about the codepen, I'm new to react and I'm a bit lost.
https://codepen.io/davide77/pen/xxrRdZR?editors=1010
<div className="pagination-container">
<div className="pagination-left">
<span>{total} results found</span>
</div>
<div className="pagination-right">
<div className="pagination-current">
Page {pageNo + 1} of {maxPages}
</div>
<div className="pagination-buttons">
<div className="pagination-button-wrapper">
<button onClick={onPrev} className="pagination-button">
<
</button>
</div>
</div>
<div className="pagination-buttons">
<div className="pagination-button-wrapper">
<button onClick={onNext} className="pagination-button">
>
</button>
</div>
</div>
</div>
There is a problem on your useEffect. You wrote:
useEffect(() => {
getMovies();
}, [pageNo]);
But should be:
useEffect(() => {
getMovies(keyword, pageNo);
}, [pageNo, keyword]);
Why? Because every time you change pageNo, useEffect will be fired but if you don't pass to the function the new page value, getMovies will return always with films of the first page.
Then, of course, pageNo should start from 1:
const [pageNo, setPageNo] = useState(1);
And of course you should change this div (is not necessary to do pageNo - 1)
<div className="pagination-current">
Page {pageNo} of {maxPages}
</div>
Here your codepen modified.
Just use react-bhx-pagination to do this easily passing a json or the endpoint. Everything will work
Repo: react-bhx-pagination
Example: Online Demo

How can I change React state from nested dynamically created components?

I am pulling project info from database and then based on how many projects I have, I push to an array and render. The problem is for some reason the "dropdownOptions" will not toggle between showing and hiding.
I basically just want to be able to click the dropdown arrow and have it show options like "delete" or "settings". Also not sure if I need to have a separate id for each project component created.
Code Snippets:
// Using hook to set display of dropdown to false
const [dropdownOptions, setDropdownOptions] = useState(false);
// This piece automatically renders clickable projects from database
const pList = [];
for (var i = 0; i < project_list.length; i += 1) {
var projectName = project_list[i]
pList.push (
<div className="projects" key={i}>
<div className="projectName">Name: <div className="projectText">{projectName}</div></div>
<div className="projectDate"> Date Created: <div className="projectText">{date}</div></div>
<div className="projectLabels">LabelsLeft:</div>
<div className="drop">
<div className="dropArrow" onClick{setDropdownOptions(!dropdownOptions)}>
{dropdownOptions ? <ProjectDropdown/> : null}
</div>
</div>
</div>
);
};
setpList(pList);
})
// Then I simply render the component "pList"
return (
<div className="container">
<div className="projectsContainer">
<div className="projectsTitle">
Projects:
<div className="addProject" onClick={toggleShow}></div>
</div>
{pList}
<div className="message">
{message}
</div>
</div>
</div>
)
Ideal look would be this before user presses droparrow on project
And this afterwards, but only for the project clicked
You have to options to such problems:
1- make a state for each item in the list, and for each one you have a boolean that can tell if that item has its dropdown opened or not
2- make single state item, but make it a number that represents the clicked on item id, when that id matches the state you open the dropdown for that item
const [selectedItem, setSelectedItem] = useState(-1);
and in your jsx
<div className="projects" key={i}>
<div className="projectName">Name: <div className="projectText">{projectName}</div></div>
<div className="projectDate"> Date Created: <div className="projectText">{date}</div></div>
<div className="projectLabels">LabelsLeft:</div>
<div className="drop">
<div className="dropArrow" onClick{()=>setSelectedItem(i)}>
{selectedItem == i ? <ProjectDropdown /> : null}
</div>
</div>
</div>
And as an advice, it's preferable to add a real id taken from your API, because the key passed to each item is so important for react, not only for showing the dropdown.
Suggested solution code
function TestSolution() {
// Using hook to set display of dropdown to false
const [selectedItem, setSelectedItem] = useState(-1);
// This piece automatically renders clickable projects from database
const pList = project_list.map((projectName, i) => (
<div className="projects" key={i}>
<div className="projectName">Name: <div className="projectText">{projectName}</div></div>
<div className="projectDate"> Date Created: <div className="projectText">{date}</div></div>
<div className="projectLabels">LabelsLeft:</div>
<div className="drop">
<div className="dropArrow" onClick{() => setSelectedItem(i)}>
{selectedItem == i ? <ProjectDropdown /> : null}
</div>
</div>
</div>
))
// Then I simply render the component "pList"
return (
<div className="container">
<div className="projectsContainer">
<div className="projectsTitle">
Projects:
<div className="addProject" onClick={toggleShow}></div>
</div>
{pList}
<div className="message">
{message}
</div>
</div>
</div>
)
}
Thinking in react is different, don't use a new state for some data if you can derive it from another state or data, that will make your life easier.

classes not being added in React using className

I am learning React on the fly for a project and am having trouble adding classes to already existing components. I have checked other SO threads and looked through tutorials on the react site - it looks like I am doing it correctly with the className but it is not working. For example, in my Event.js:
render: function() {
return (
<div>
<article>
<div className="row">
{ this.drawOrderError() }
<div className="large-4 columns event-img-div">
<img src={ this.props.image }/>
</div>
<div className="large-8 columns event-right-column">
{ this.state.showCreditCard ? this.drawCreditCard() : this.drawTicketing() }
<br />
<div className="event-detail">
<div className="row">
<div className="large-12 column">
<span className="ticket-column-headings">Event Details</span>
<p className="event-details">{this.props.description}</p>
</div>
</div>
</div>
</div>
</div>
</article>
{ this.drawOrderSummaryOverlay() }
</div>
);
}
I have added the class event-img-div - but when I go to the browser I do not see it added in console, and cannot apply styles to that class. What am I doing wrong? Can provide more code if needed.
I am changing the files in a local directory and running on local host, using gulp to start the server.

React JS + ALT (Flux): Understanding Invariant Violation findComponentRoot(..., .0.1.1.0.4.2.0.1.1): Unable to find element

I am using REACT JS with a FLUX IMPLEMENTATION called ALT.
I started with a working React Component:
ConfirmEditModal = React.createClass({
getInitialState(){
console.log('ConfirmEditModal - getInitialState');
var state = {sample: 'MY_SAMPLE_STATE'};
console.log(state);
return state;
},
onChange(state){
console.log('ConfirmEditModal - onChange');
console.log(state);
this.setState(state);
},
componentDidMount(){
console.log('ConfirmEditModal - componentDidMount');
//SeedStore.listen(this.onChange);
},
componentWillUnmount(){
//SeedStore.unlisten(this.onChange);
},
render(){
return (
<div className="ui modal edit">
<i className="close icon"></i>
<div className="header">Form For Editing</div>
<div className="content">
<div className="ui form">
<h4 className="ui dividing header">Birth Information</h4>
<div className="field">
<label>Name</label>
<input name="name" type="text" placeholder="Name"></input>
</div>
</div>
</div>
</div>
);
}
});
Pls note the commented out code of SeedStore.listen(this.onChange) and SeedStore.unlisten(this.onChange).
the above code works as long as those 2 lines are commented out.
Those 2 lines are the code required to listen to the store using ALT (FLUX IMPLEMENTATION).
If I uncomment those 2 lines I will end up with this code:
ConfirmEditModal = React.createClass({
getInitialState(){
console.log('ConfirmEditModal - getInitialState');
var state = {sample: 'MY_SAMPLE_STATE'};
console.log(state);
return state;
},
onChange(state){
console.log('ConfirmEditModal - onChange');
console.log(state);
this.setState(state);
},
componentDidMount(){
console.log('ConfirmEditModal - componentDidMount');
SeedStore.listen(this.onChange);
},
componentWillUnmount(){
SeedStore.unlisten(this.onChange);
},
render(){
return (
<div className="ui modal edit">
<i className="close icon"></i>
<div className="header">Form For Editing</div>
<div className="content">
<div className="ui form">
<h4 className="ui dividing header">Birth Information</h4>
<div className="field">
<label>Name</label>
<input name="name" type="text" placeholder="Name"></input>
</div>
</div>
</div>
</div>
);
}
});
and I get this error:
Error: Invariant Violation: findComponentRoot(..., .0.1.1.0.4.2.0.1.1): Unable to find element. This probably means the DOM was unexpectedly mutated (e.g., by the browser), usually due to forgetting a <tbody> when using tables, nesting tags like <form>, <p>, or <a>, or using non-SVG elements in an <svg> parent. Try inspecting the child nodes of the element with React ID ``.
I would like to understand what is going on behind the scenes that would be causing this error, because as far as I can understand it....listening to a store just means that you listen to any state changes in the store and that's it....it has got nothing to do with parent child components and FINDING ELEMENTS.......
What's the explanation behind this error?
I would not have thought that listening to a store would affect finding of elements as the error suggests.
Other stackOverflow articles Q/A on this suggests that there are changes in the DOM that is not intended.....but listening to a store should not affect the DOM right??? thus my confusion.....
What's the logic and explanation behind this error?

Resources