I am learning react and I found a video on youtube of someone creating a PWA using a news api, I decided I would try replicate it using react as his video was just in vanilla JS and I learn things a little easier if I build stuff.
on the news API there is a sources and an articles API.
Articles:
https://newsapi.org/v1/articles?source=bbc-news&apiKey=${API_KEY}
Sources:
https://newsapi.org/v1/sources?language=en
I have created a select box which contains the sources from the sources api and I get the news by updating the source in the URL from the select box. I have managed to get the select box to put its value into state onchange but I cant get that up to the NewsItem component to change the source in the articles url.
I have put a codepen together here https://codepen.io/crash1989/pen/JZLQxr it is slightly different to how I have my code, as I have had to create the sources and news manually as I didnt want to publish my API key.
Where you see componentDidMount I am using async/await functions to get the data from the API and putting it into state.
In my actual code I want to have a url like this for the articles https://newsapi.org/v1/articles?source=${this.state.source}&apiKey=${API_KEY}
so the bottom line is I need help getting the select box value into the NewsItem component to update my news.
Your App is build like this
<App>
<Nav />
<News />
</App>
You select a value in <Nav /> and want to pass it to <News />. You should do so by storing the value in the state of App, and pass the value and the changeHandler as property to the children.
class App extends Component {
constructor(props) {
this.state = {
source: "BBC News"
}
}
setSource = source => {
this.setState({source})
}
render() {
let {source} = this.state
return (
<div>
<Nav source={source} setSource={this.setSource} />
<News source={source} />
</div>
)
}
}
Related
I am very new to react and just started to build a basic crud application with it. Everything is done besides the update functionality, i got stuck there.I have several bootstrap cards with 2 buttons , delete and update.The data comes from a mysql database and was persisted with hibernate (spring boot on backend).The update button when pressed should pass the id and render a new component(on a different route, guess i need to use Link here) in which a filled form with the respective objects details is presented. Once the user updates the form and clicks submit, he should be redirected to the Cards page. So far i am stuck at the button + Link and rendering the new component phase and for some reason i can't seem to understand how to make it work.This is my code so far
this is my JSX in which i have the Update button which is in the render method of CarList component which has all the cards.
<ReactBootstrap.Card.Body>
<ReactBootstrap.Card.Title>{cars.mark}-{cars.model}</ReactBootstrap.Card.Title>
<ReactBootstrap.Card.Header>Price: {cars.price}</ReactBootstrap.Card.Header>
<br />
<h6>Fabricated: {cars.year}</h6>
<h6>{cars.fuel}</h6>
<ReactBootstrap.Button variant="success" className="cardButtons" id="cardButtonGreen" onClick={() => this.handleClickUpdate(cars.id)}> Update</ReactBootstrap.Button>
<ReactBootstrap.Button variant="danger" className="cardButtons" id="cardButtonRed" onClick={() => this.handleClickDelete(cars.id)}> Delete</ReactBootstrap.Button>
</ReactBootstrap.Card.Body>
</ReactBootstrap.Card>
</div>
}
<br />
</div>
this is my CarList class and the constructor
class CarList extends Component {
constructor(props) {
super(props)
this.state = {
cars: [],
error: "",
deleteError: "",
updateError: "",
updateCarId: null,
buttonWasPressed: false
}
}
here i have the function that is triggered on click.I am sating the state to the id of the object that is in that specific card where the update button is.
handleClickUpdate = (carId) => {
console.log(carId);
this.setState(
{
updateCarId: carId,
buttonWasPressed: true
}
)
}
and lastly i am rendiring the Component MyComp i want to render by passing in the ID.Line is located in component CarList right under where the Card is.
{this.state.buttonWasPressed && <MyComp carId={this.state.updateCarId} />}
What this code gives me so far, is that i am able to set the state as the id, and then use the button to display the component, but it is displayed on the same page, right under the card (where the line of code is also located) instead of displaying it in a new page on a new route.I have tried adding Link,Switch, Route, Router, but i am afraid i am not sure how to use it in this exact context with the button, and it is confusing to me so i was not able to make it work.Can you please help me render "MyComp" on a new page with that id ?
Any help would be greatly appreciated.
what you need is a global store, such as Redux or Mobx. That way you can update the state with relevant data and retrieve them on the new page.
If you need a workaround, you could use history.pushState()
Basically you can push to your location and with it a state.
And on the next page, which is MyComp in this case, you could use history.state to retrieve the pushed data.
I'm new to React, I didnt know how to call the problem I'm facing
I have a list of friends, and when the list is empty a message is displayed indicating "Add friends to be displayed here"
and when I add a friend the message should dissapear
the thing is that I need to do it with a life cycle method, like componentDidUpdate() for example.
The functionality is there, but as in the title, 1 turn or movement as I call it later
I will explain:
I see the message to add friends, but when I click to add a friend it doesnt dissapear until I add a second friend.
And the message doesnt reapears when I delete all the friends, but when I add new friend, so its a turn latter, I do a thing and in the next movement the component is rerendered
I'm sure its something simple, but I have been struggling with it for two days and I cant find how to make it work instantly.
here is the code
import React, { Component } from 'react';
import Title from './title';
/* I'm using this var, because when I try to set it with a state I get an infinite loop */
var title = "Add friends to view them here";
class FriendList extends Component {
constructor(props){
super(props)
}
componentWillReceiveProps(nextProps){
/* friendList is an array with friends objects */
if(this.props.friendList.length > 0){
console.log("this is "+ title);
title = "";
}else{
title = "Add friends to view them here";
console.log("this is "+ title);
}
}
render(){
let friends = this.props.friendList;
return(
<div className="friend-list">
<p>{title}</p>
<div>
{Object.keys(friends).map((key) => {
var friend = friends[key];
return (
<div className="friendData">
<img className="friendPhoto"src={friend.profilePic} alt={friend.profilePic}/>
<div className="friend">
{friend.name}
<br/>
{friend.city}
</div>
<button className="delete" onClick={() => this.props.deleteFriend(friend)} >X</button>
</div>
);
}
)}
</div>
</div>)
}
}
export default FriendList;
You can conditionally render the title
<p>{this.props.friendList.length === 0 ? title : null}</p>
Instead of
<p>{title}</p>
Please include a screenshot of the Browser React Debugger extension with all the variables,state,props expanded.
It might be that your component is not re-rendering. I had this kind of issue before.
Also, can you try closing the developer tools (F12). I had an issue before where my app does 1 tick only if my Dev Tool is open.
Where my element is supposed to change color only when I hover-in, and back to original color when I hover-out, but when my dev tools is open, it's stuck to the changed color even if I already hover-out.
By default the ChipField can only show the content of a field, at least this is what the documentation tells. The example below displays the contents of the field name.
<ReferenceArrayField source="substances" reference="substances" label="Substanzen">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>
However, I want ChipField to display a text combined of information from several fields:
const Substanz = ({ record }) => {
return record.name+" ("+record.unit+")";
};
<ReferenceArrayField source="substances" reference="substances" label="Substanzen">
<SingleFieldList>
<ChipField source={<Substanz />} /> <---- this does not work!
</SingleFieldList>
</ReferenceArrayField>
but unfortunately, source only accepts a field name, not an object like the OptionText prop of the SelectInput field.
What is the expected way to do this?
I think you are almost there with your custom SubstanzField component. Just use MUI styled component to make your own ChipField-like looking component and pass it directly inside of the SingleFieldList
MUI Chips docs
Don't know if you expected more sophisticated solution but this should be simple and flexible enough for your case.
I am facing a problem in route how to render the same component in multiple nav link.
I have 2 nav link like this. when I click on edit product, the component render with detail successfully. After that, I click on add a product then component does not render again because component already rendered on the edit product link.
I am using the same component for add and edit.
Anyone can tell me how to Re-render that component on the next click.?
Thanks in advance
<Route
path="/addproduct"
render={() => {
return userData.is_superuser === true ? (
<Product />
) : (
<Redirect to="/dashboard" />
);
}}
/>
<Route path="/editproduct/:id" component={Product} />
Try using render property as follows
<Route path="/editproduct/:id" render={() => <Product/> } />
did you wrap your routes with Switch component?
Just an extra info, you should take a look at react lazy/suspense, is used for code splitting, is useful for decreasing SPAs load times.
I found how to resolve this problem.
You need to use componentWillReceiveProps function in your component.
clicked a link first time by calling url www.example.com/content1/ componentDidMount() is run.
Now when you click another link say www.example.com/content2/ same component is called but this time prop changes and you can access this new prop under componentWillReceiveProps(nextProps) which you can use to call API Or make state blank and get new data.
componentWillReceiveProps(nextProps){
//call your API and update state with new props
}
Please take a look at my code for Dropdown,
I'm using the semantic ui react dropdown on an EditProfile component. I have pasted a sample code here, https://codesandbox.io/s/m4288nx4z8, but I could not get it to work because I'm not very familiar with functional components in React, I've always used Class component. But you can check the full code for the whole component below in the github gist.
https://gist.github.com/mayordwells/b0cbb7b63af85269091f1f98296fd9bb
Please, I need help on inserting values from multiple select options of a Dropdown into the Database and also a way to display that back upon viewing the profile edit page again.
I'm using semantic-ui-react in react + rails app.
Also when I insert a value using a normal drop down without multiple select, the value gets persisted into the database.
<Dropdown
placeholder='Select Country'
fluid
search
selection
options={countryOptions}
name='country'
defaultValue={this.state.extraInfo.country}
onChange={(e) => this.handleExtraInfoChange('country', e)}
/>
This code handles change for the dropdown elements.
handleExtraInfoChange = (name, event) => {
let value;
if (event.target.value !== undefined) {
value = event.target.value;
} else {
value = event.target.textContent;
}
let newExtraInfo = Object.assign(this.state.extraInfo, { [name]: value })
this.setState({ extraInfo: newExtraInfo});
}
But when I visit the page again, I get a white blank in the input box. Here's a screen pic for that. When I comment out the defaultValue or value property(i have tried with defaultValue and value), the white blank disappears, but the value picked by a user is also not seen.
Please advice what is a possible solution to this misbehavior? And what is the best way to insert multiple values into the Database?
Thanks in advance for your time.
A functional component does not have state, it's used for composition; you want to store state, so you either have to create a Component class or you need an external state container like redux.