React component renders 1 turn latter - javascript

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.

Related

Take a specific value of a map array in reactJS

i am working with a REST API that provides data for different countries. I have a search box and when i am typing letters under the box appeared different countries that matches with the search. Each country that appears has a button beside and when you click that button some information about this country appears. I have two different components, the first component showing the countries that matches the search and the second component showing the information from the selected country.
The code of the first component:
import {useState} from 'react'
import TheCountry from './TheCountry'
const TheSearchCountry= ({countrie}) => {
const [buttonClicked, setButtonClicked] = useState(true)
return (
buttonClicked ?
countrie.map(country => (
<p key={country.name}>
{country.name}
<button onClick={() => {setButtonClicked(false)}}>show</button>
</p>
))
: <TheCountry countries={countrie} />
)
}
export default TheSearchCountry
The second component called
<TheCountry/>
When the user clicks the show button i want to call the component
<TheCountry/>
and show in the screen the details about this particular country. But something like this did not happen, i screen all the data for all the countries that matches the search query. I did not find a correct way to call my component and isolate the country that trigger the button. Can anyone help ?

Unable to render component in a new page on a new route on button click

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.

Agm direction panel: Show panel in different component

I have two components that display on one page (first is 70% of the page, the other 30%). One in which the map is and another where I want to show the panel (info on how to get to the destination: turn left, then right, etc.)
I used agm-directions to get the panel - https://robby570.tw/Agm-Direction-Docs/source/featured/direction.html (look at Update Panel With New Query ).
I managed to create it well and, when you click a button the panel will appear with the text, but on the map component, under the map (see picture 2). This is because I put <div #myPanel></div> under the map in the first component.
I want to get that panel text on the second component. I do not know how to do this because I bind the panel in the map component [panel]="myPanel", according to the documentation above.
So is there a way I can transfer that bonded data in a different component ?
Here is the first component html:
<agm-map [zoom]="zoom" [latitude]="lat" [longitude]="lng">
...
<agm-direction
[origin]="origin"
[destination]="destination"
[travelMode]="transitOptions"
[visible]="show"
[renderOptions]="renderOptions"
[markerOptions]="markerOptions"
[panel]="myPanel" <!-- THIS IS IMPORTANT FOR INFO -->
>
</agm-direction>
...
</agm-map>
<div #myPanel></div>
The second component is just some generic html.
TLDR: How can I get <div #myPanel></div> to work in a different component when I bind [panel]="myPanel" in agm-direction.
Managed to get the value thanks to
#ViewChild("myPanel", {static: false}) myPanel;
Then, in a function that activates when the button is clicked:
let _this = this;
setTimeout(function() {
console.log(_this.myPanel);
if(_this.myPanel != undefined){
let ivan = _this.myPanel;
console.log("test myPath", ivan);
//console.log("Test", JSON.stringify(this.myPanel.nativeElement.innerHTML));
console.log(_this.myPanel.nativeElement.innerHTML); //THIS IS THE ANSWER
}
}, 500);

React update url using selectbox on change

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>
)
}
}

React components rendering incorrectly

I have a react project, a recipe box, which includes the ability to open a recipe and add/delete ingredients. Here is a fiddle. You can click the recipe name to open the recipe. There is an edit button which reveals the delete button and gives the option to change the name of the ingredients. When the 'delete ingredient' button is pressed, the last ingredient appears to always be deleted, regardless of which ingredient is selected, but when the 'done' button is clicked and the editable input boxes change back to text, the correct change is shown, the proper ingredient deleted and the last ingredient remains. Though this works functionally, it's obviously not very UI friendly, and I wondered why this was happening. Any help would be great.
jsFiddle
class Input extends React.Component {
render() {
const array = this.props.update;
let booleanButton = null;
if (this.props.ingr) {
////////////////////////////
// here is the button's JSX
booleanButton = <button onClick=
{this.props.handleDeleteIngredient.bind(this, array)}>delete
ingredient</button>;
///////////////////////////
}
return (<div><form><input type="text" defaultValue={this.props.text}
onChange={this.props.onChange.bind(this, array)} /></form>{booleanButton}
</div>)
}
}
And the handler:
handleDeleteIngredient(data, e ) {
var key = data[2];
var ingrs = this.state.ingrs;
ingrs.splice(key, 1);
this.setState({ingrs:ingrs});
}
Your description is quiet confusing, and according the your fiddle code I think your problem is caused by not setting a good key for your list Item.
from what it looks in this line, you don't have a key={ingrs[i]} props, try set it to id see it will work, but making ingrediant name as key is probably not a good idea, try to give an actual id.
ingrList.push(<Input key={ingrs[i]} handleDeleteIngredient={this.handleDeleteIngredient.bind(this)} id={id} update={[this.props.objectIndex, "ingrs", i]} onChange={this.onInputChangeIng.bind(this)} text={ingrs[i]} />);

Categories