So, I have this function called !HandleDetail that gets the item once clicked and loads a detail screen. When this reloads, it shows only one object no matter what object I clicked on. So if I clicked on a iPhone, and I reload the browser, it reloads with the only item (a T-shirt) object showing. I am sure this has something to do with state as I fixed other bugs like this using state. I am thinking I have to map over the created array to gather the information and set the state of it. Here is a video showing what I mean: https://tyriquedaniel14-gmail.tinytake.com/tt/MzYwMDcwN18xMDg4NTEzMQ. To make things clear, I am trying to have the detail state show the corresponding item with the same id.
state = {
products: [],
clothing: [],
gadget: [],
smoke:[],
detailProduct: detailProduct,
cart: [],
modalOpen: false,
modalProduct: detailProduct,
cartSubTotal: 0,
cartTax: 0,
cartTotal: 0
};
getItem = id => {
const product = this.state.products.find(item => item.id === id);
return product;
};
handleDetail = id => {
const product = this.getItem(id);
this.setState(() => {
return { detailProduct: product };
});
};
export const detailProduct = {
id: 1,
title: "COMME DES GARCONS TEE",
img: "img/product-1.png",
img2: "img/product-1-1.png",
img3: "img/product-1-2.png",
img4: "img/product-1-3.png",
luxury: "All Luxuryitems are inspected to verify authenticity",
price: 200,
info: " COMME DES GARCONS PLAY BASIC LOGO TEE",
inCart: false,
count: 0,
total: 0,
size1: "Small",
size2: "Medium",
size3: "Large",
size4: "Extra Large",
fabric: "100% Cotton",
category: "Mens Fashion"
};
This is My router link
<Link to="/details">
I am trying to turn this into an array of all products.
I have tried adding the map method and setting detailProduct to product.
It is the normal behaviour in the react state, if you refresh the page the state becomes the initial state as you set it to your const with the detailProduct of your t-shirt, if you want to show a specific item based on the click you need to add the id to the url, because everytime you refresh the page your state is reseted so no record of the actions you did clicking.
Use a url with the id like details/id that way your app can remember the item you visited
Related
Context
I am trying to save my collection of my drawn features dynamically into a state hook, and keeping them updated from onCreated, onEdited and onDeleted.
This is how my UI looks like:
Problem
The issue happens when, I click on the trash icon and remove one of the created features with (let's say) id=2, and then create another new feature of id=3; it looks like the onCreated method doesn't have it's state of features updated, and when creating the feature of id 3, it returns to show the deleted figure of id 2 in the data (but not on the map).
This is how it looks like when the old figure is deleted, but when creating a new one, the onCreate makes it persistent in the data displayed at the right container.
This is the code that I run: (The featureCollection is the state hook passed from the App.js):
import { FeatureGroup } from "react-leaflet";
import { EditControl } from "react-leaflet-draw";
export default function EditFeature({ lkey, setlKey, featuresCollection, setFeaturesCollection }) {
const _onCreated = (e) => {
let layer = { id: e.layer._leaflet_id, ...e.layer.toGeoJSON() };
setlKey(e.layer._leaflet_id);
setFeaturesCollection({
...featuresCollection,
features: [layer, ...featuresCollection.features]
});
};
const _onDeleted = (e) => {
let unwanted = Object.keys(e.layers._layers);
unwanted = unwanted.map(item => Number(item));
// Filter out those layers whose id is in the unwanted array
let filtered = featuresCollection.features.filter(e => !unwanted.includes(e.id));
setFeaturesCollection({
...featuresCollection,
features: [...filtered]
});
};
return (
<FeatureGroup>
<EditControl
key={lkey}
id="EditControl"
onCreated={_onCreated}
onDeleted={_onDeleted}
position="topright"
draw={{
circle: false,
circlemarker: false,
polyline: false,
marker: false,
polygon: {
allowIntersection: false,
shapeOptions: {
color: "purple",
weight: 3
},
},
rectangle: {
shapeOptions: {
color: "purple",
weight: 3
}
}
}}
/>
</FeatureGroup>
);
};
My main goal is to achieve that my state keeps updated the figures shown in the map, in order to then export those to a geojson file, like the web GeoJSON.io does! (within React tho).
Reference:
https://github.com/alex3165/react-leaflet-draw/issues/154
I am using React Table 7 to create a table with the first cell of each row being a ChecOut/CheckIn Button. My goal is to create a tool where people can CheckOut and CheckIn equipment. My React Table CodeSandbox
The idea is that when a user clicks the button, it will change from "CheckOut" to "CheckIn" and vise versa. It will also change the color of the row when Checked out. I was able to accomplish this with JQuery (code is in the sandbox under the App() functional component) but want to avoid that and am sure it's easily doable in react.
My issue is changing the state of an individual button and which functional component to define it in. The <Button> elements are created dynamically by the React-Table, defined in the columns object under the App functional component.
{
Header: "CheckIn/Out",
Cell: ({ row }) => (
<Button
key={row.id}
id={row.id}
onClick={e => checkClick(e)}
value={checkButton.value}
>
{checkButton.value}
</Button>
)
}
I tried passing a function to onChnage attribute on the <Button> element. In that function I updated the state of the <Button> to change the string value from "CheckOut" to "CheckIn" but that does not work. At first, that changed the name (state) of All the <Button> elements. Not sure if the state will live in the App() component or the TableRe() functional component. Or do I need to use state at all?
I basically built this on top of the editable table code available on the React-Table website React-Table Editable Data CodeSandbox , examples section React-Table Examples .
Any help is much appreciated!
data.js
import React from "react";
// export default random => {
// let arr = [];
// for (let i = 0; i < random; i++) {
// arr.push({
// first: chance.name(),
// last: chance.last(),
// birthday: chance.birthday({ string: true }),
// zip: chance.zip()
// });
// }
// return arr;
// };
const temp_data = [
{
firstName: "johny",
lastName: "Bravo",
age: "23",
visits: "45",
progress: "complete",
status: "all done"
},
{
firstName: "johny",
lastName: "Bravo",
age: "23",
visits: "45",
progress: "complete",
status: "all done"
}
];
const ArrayData = () => {
const data = temp_data.map(item => {
return {
firstName: item.firstName,
lastName: item.lastName,
age: item.age,
visits: item.visits,
progress: item.progress,
status: item.status
};
});
return data;
};
// Do not think there is any need to memoize this data since the headers
// function TempData() {
// const data = React.useMemo(ArrayData, []);
// return data;
// }
export default ArrayData;
I have a table built with antd in react. I am getting the data from an API endpoint. Everything else works fine. But when i click one row at the table, all the rows are getting selected. The row selection is working fine with constant data of antd documentation. But when i plug it in my code with dynamic data rendering it just goes crazy and selects every row whenever I click on only one row.
Here is my state :
class TabularView extends React.Component {
intervalID;
state = {
selectedRowKeys: [],
loading: false,
data: [],
columns : [],
length : '',
approve : '',
perc : '',
icon : <ArrowUpOutlined/>,
color : '',
visible: false
}
Here is my other functions for the row selection
start = () => {
this.setState({ loading: true });
setTimeout(() => {
this.setState({
selectedRowKeys: [],
loading: false,
});
}, 1000);
}
onSelectChange = selectedRowKeys => {
console.log('selectedRowKeys changed: ', selectedRowKeys);
this.setState({ selectedRowKeys });
}
And here is my render part for the rowselection
render(){
const { loading, selectedRowKeys } = this.state;
const rowSelection = {
selectedRowKeys,
onChange: this.onSelectChange,
};
return(
<Table rowSelection={rowSelection} columns={this.state.columns} dataSource={this.state.data} pagination={{ pageSize: 20 }} />
)}
Use an unique key prop to each child to avoid this kind of problem
Each and every react chield or any map function you use. If you do not provide a unique key prop to it. It will give a warning.
React always understand it's children by the key prop. So as all the key to the table is the same. As you selecting one row, as the key is same it is selecting all the row. Key prop in react is very much useful for dynamic programming using map function. Please read this for more clarification - React Key Prop
You have to add key on your dataSource object.
I have this state:
state = {
formdata:{
name: null,
about: null,
price: null,
offerPrice:null,
playStoreUrl:null,
appStoreUrl:null ,
photo:null,
}
}
what I want: update form inside modal i used it to update products. I used new props inside componentWillReceiveProps
I did:
componentWillReceiveProps(nextProps){
let Updateproduct = nextProps.productlist.productlist.Products;
Updateproduct.map((item,i) => {
let formdata = Object.assign({}, this.state.formdata);
formdata.name = item.name
formdata.about = item.about
formdata.price = item.price
formdata.offerPrice = item.offerPrice
formdata.playStoreUrl = item.playStoreUrl
formdata.appStoreUrl = item.appStoreUrl
formdata.photo = item.photo
console.log(formdata)
this.setState({formdata})
})
}
MyProblem: this filled the objects but in the form inside modal only I saw the last product not all in modal when click to update any product it. Note:Updateproduct contains:
{
about: "about product1"
appStoreUrl: "https://itunes.apple.com/us/app/snapchat/id447188370?mt=8"
name: "p1"
offerPrice: 99.99
photo: "images/products/"
playStoreUrl: "images/products/"
price: 1000
}
{
about: "about product2"
appStoreUrl: "https://itunes.apple.com/us/app/snapchat/id447188370?mt=8"
name: "p2"
offerPrice: 99.99
photo: "images/products/"
playStoreUrl: "images/products/"
price: 2000
}
Issue is, you want to store single specific product item clicked by user in state variable, but with current code you are always storing the last product item. Also setState in loop is not a good way.
To solve the issue, store the clicked product detail in state inside onClick handler function only, instead of componentWillReceiveProps method. For that you need to bind the product id with onClick function.
Like this:
onClick={this.getProductId.bind(this, item.id)}
// click handler function
getProductId = (id) => {
let productObj = {};
let Updateproduct = this.props.productlist.productlist.Products;
Updateproduct.forEach((item,i) => {
if(item.id == id) {
productObj = {
name: item.name,
about: item.about,
price: item.price,
offerPrice: item.offerPrice,
playStoreUrl: item.playStoreUrl,
appStoreUrl: item.appStoreUrl,
photo: item.photo
};
this.setState({ formdata: productObj, id: id })
}
})
}
You’re setting your state inside the map. If you think of the map as a loop that means you’re overriding it each iteration. So you will only ever have the last one displaying.
I think that's because your setState() call is in the wrong place (and only one object at a time):
let data =[];
UpdateProduct.map((item, i) => {
let formdata = null;
// do your formdata stuff but append it as part of an array
data.push(formdata);
});
this.setState({ formdata: data });
Then I think it should get all the products.
I have this state in my main parent component:
this.state = {
playableCards: [],
openedCard: null,
offeredChips: 0,
activePlayer: 0, // first player is 0, second player is 1
players: [
{
name: "player1",
remainingChips: 11,
cards: [],
score: null
},
{
name: "player2",
remainingChips: 11,
cards: [],
score: null
}
]
};
Now, I have some methods that change different properties of the state. E.g.:
takeCard = () => {
const {
activePlayer,
players,
playableCards,
offeredChips,
openedCard
} = this.state;
if(openedCard) {
// Add card to active player
let playersClone = [...players];
playersClone[activePlayer].cards = [
...playersClone[activePlayer].cards,
openedCard
];
// Add any offered chips to active player
playersClone[activePlayer].remainingChips += offeredChips;
this.setState({ players: playersClone }, () =>
this.calculateScore(activePlayer)
);
// Remove card from deck
this.setState({
playableCards: playableCards.filter(function(card) {
return card !== openedCard;
})
});
// Change active player
const nextPlayer = activePlayer === 0 ? 1 : 0;
this.setState({ activePlayer: nextPlayer });
// Reset offered chips to 0
this.setState({ offeredChips: 0 });
// Reset opened card
this.setState({ openedCard: null });
} else {
console.log("Open a card first!");
}
};
As you can see, there are many properties that are being changed just by a single click event (this method is attached to a click event). I am wondering whether is this the proper way of doing it or should I combine all the setState()?
Its okay to call multiple setStates since React internally does batching before setState and hence will only call render once. That said, the chances of you making a mistake in writing setState such that batching ignores a change or sets incorrect value are high(for instance you may call setState twice for the same key based on the previous value and might expect a result different from what you get). Hence its recommended that you call setState once after processing all the values
// Add card to active player
let playersClone = [...players];
playersClone[activePlayer].cards = [
...playersClone[activePlayer].cards,
openedCard
];
// Add any offered chips to active player
playersClone[activePlayer].remainingChips += offeredChips;
const playableCards = playableCards.filter(function(card) {
return card !== openedCard;
})
// Change active player
const nextPlayer = activePlayer === 0 ? 1 : 0;
// Reset offered chips to 0
// Reset opened card
// Remove card from deck
this.setState({
openedCard: null,
offeredChips: 0,
playableCards,
players: playersClone
}, () =>
this.calculateScore(activePlayer)
);
you can change multiple properties of a state like this.
this.setState({ openedCard: null, offeredChips: 0, activePlayer: nextPlayer });
you can change multiple properties of a state like this.this.setState({value1: 0, value2: 0})
For functional components, the basic syntax to update more than one property at once is as follows:
function handleUserData() {
setUserData((prevUserData) => {
return {
...prevUserData,
propertyName: theValueOrVariableHere,
otherPropertyName: theValueOrVariableHere
}
})
}