Displaying mapped data without being clicked before showing - javascript

I am having a little difficulty with my data. I was able to get all mapped data currently but without me clicking the categories, the data won't be displayed.
Here's an example:
const categoriesData = [
{
name: 'All',
label: 'All',
total: '18',
className: 'activeCategory'
},
{
name: 'Business Services',
label: 'Business_Services',
total: '18'
},
{
name: 'Design Services',
label: 'Design_Services',
total: '18'
},
{
name: 'Education Services',
label: 'Education_Services',
total: '18'
},
{
name: 'Finance Services',
label: 'Finance_Services',
total: '18'
},
{
name: 'IT Services',
label: 'IT_Services',
total: '18'
},
{
name: 'Legal Services',
label: 'Legal_Services',
total: '18'
},
{
name: 'Manufacturing',
label: 'Manufacturing',
total: '18'
},
{
name: 'Marketing',
label: 'Marketing',
total: '18'
}
];
const postsData = {
All: [
{ id: 1, name: 'Post 3' },
{ id: 2, name: 'Post 2' }
],
Business_Services: [
{ id: 1, name: 'Post 3' },
{ id: 2, name: 'Post 2' }
],
Design_Services: [
{ id: 1, name: 'Post 5' },
{ id: 2, name: 'Post 2' }
],
Education_Services: [
{ id: 1, name: 'Post 1' },
{ id: 2, name: 'Post 2' }
],
Finance_Services: [
{ id: 1, name: 'Post 1' },
{ id: 2, name: 'Post 2' }
],
IT_Services: [
{ id: 1, name: 'Post 1' },
{ id: 2, name: 'Post 2' }
],
Legal_Services: [
{ id: 1, name: 'Post 1' },
{ id: 2, name: 'Post 2' }
],
Manufacturing: [
],
Marketing: [
{ id: 1, name: 'Post 1' },
{ id: 2, name: 'Post 27675' }
]
};
function fakePostsApi(catName) {
return new Promise((resolve) =>
setTimeout(() => {
resolve(postsData[catName]);
}, 1000)
);
}
function Main() {
const [categories, setCategories] = React.useState(categoriesData);
const [catName, setCatName] = React.useState();
const [posts, setPosts] = React.useState([]);
React.useEffect(() => {
if (catName) {
fakePostsApi(catName)
.then(setPosts);
}
}, [catName]);
return (
<div>
{categories.length > 0 ? (
categories.map((category, i) => {
return (
<button key={i} onClick={() => setCatName(category.label)}>
{category.name}
</button>
);
})
) : (
<p>Loading...</p>
)}
<div>
{posts.length === 0 ? (
<p>No posts...</p>
) : (
posts.map((post) => <div key={post.id}>{post.name}</div>)
)}
</div>
</div>
);
}
ReactDOM.render(
<Main />,
root
)
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<div id="root"></div>
My main problem is: I want the values of all to be displayed first(just like active status) when page loads without being clicking the All button.

Set the default value of catName to be the label of the 0 item of the categories:
const [catName, setCatName] = React.useState(categories[0] && categories[0].label);
Or optional chaining (?.) if supported:
const [catName, setCatName] = React.useState(categories[0]?.label);
const categoriesData = [{"name":"All","label":"All","total":"18","className":"activeCategory"},{"name":"Business Services","label":"Business_Services","total":"18"},{"name":"Design Services","label":"Design_Services","total":"18"},{"name":"Education Services","label":"Education_Services","total":"18"},{"name":"Finance Services","label":"Finance_Services","total":"18"},{"name":"IT Services","label":"IT_Services","total":"18"},{"name":"Legal Services","label":"Legal_Services","total":"18"},{"name":"Manufacturing","label":"Manufacturing","total":"18"},{"name":"Marketing","label":"Marketing","total":"18"}];
const postsData = {"All":[{"id":1,"name":"Post 3"},{"id":2,"name":"Post 2"}],"Business_Services":[{"id":1,"name":"Post 3"},{"id":2,"name":"Post 2"}],"Design_Services":[{"id":1,"name":"Post 5"},{"id":2,"name":"Post 2"}],"Education_Services":[{"id":1,"name":"Post 1"},{"id":2,"name":"Post 2"}],"Finance_Services":[{"id":1,"name":"Post 1"},{"id":2,"name":"Post 2"}],"IT_Services":[{"id":1,"name":"Post 1"},{"id":2,"name":"Post 2"}],"Legal_Services":[{"id":1,"name":"Post 1"},{"id":2,"name":"Post 2"}],"Manufacturing":[],"Marketing":[{"id":1,"name":"Post 1"},{"id":2,"name":"Post 27675"}]};
function Main() {
const [categories, setCategories] = React.useState(categoriesData);
const [catName, setCatName] = React.useState(categories[0] && categories[0].label);
const [posts, setPosts] = React.useState([]);
React.useEffect(() => {
if (catName) {
fakePostsApi(catName)
.then(setPosts);
}
}, [catName]);
return (
<div>
{categories.length > 0 ? (
categories.map((category, i) => {
return (
<button key={i} onClick={() => setCatName(category.label)}>
{category.name}
</button>
);
})
) : (
<p>Loading...</p>
)}
<div>
{posts.length === 0 ? (
<p>No posts...</p>
) : (
posts.map((post) => <div key={post.id}>{post.name}</div>)
)}
</div>
</div>
);
}
function fakePostsApi(catName) {
return new Promise((resolve) =>
setTimeout(() => {
resolve(postsData[catName]);
}, 1000)
);
}
ReactDOM.render(
<Main />,
root
)
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<div id="root"></div>

Related

ReactJS render dynamic nested arrays of data

How can i render dynamic nested data in ReactJS? This array sample contains nested childs, each item have the same structure. There is a way to render this data recursively?
function App () {
const [data, setData] = useState([
{
id: '1',
name: 'demo1',
programParent: '',
childs: [
{
id: '2',
name: 'dem2',
programParent: '1',
childs: [
{
id: '4',
name: 'demo4',
programParent: '2',
childs: [
{
id: '5',
name: 'demo5',
programParent: '4'
}
]
}
]
},
{
id: '3',
name: 'demo3',
programParent: '1'
}
]
},
{
id: '6',
name: 'demo6',
programParent: ''
}
])
return (
<>
<div>
{
data.length &&
data.map(item => (
<div key={item.id}>
<h3>{item.name}</h3>
{
item.childs?.length && (
item.childs.map(child => (
<div key={child.id}>
<h4>-{child.name}</h4>
{
child.childs?.length && (
child.childs.map(childChild => (
<div key={childChild.id}>
<h5>--{childChild.name}</h5>
</div>
))
)
}
</div>
))
)
}
</div>
))
}
</div>
</>
)
}
export default App
You will need to render them recursively. Here is something to give you an idea, you can further customize the rendering.
import React from 'react';
import './style.css';
let Tree = ({ data }) => {
return (
<div>
{data.map((x) => {
return (
<div key={x.id}>
{x.name}
{!!x.childs?.length && (
<div style={{ marginLeft: 10 }}>
<Tree data={x.childs} />
</div>
)}
</div>
);
})}
</div>
);
};
export default function App() {
const [data, setData] = React.useState([
{
id: '1',
name: 'demo1',
programParent: '',
childs: [
{
id: '2',
name: 'dem2',
programParent: '1',
childs: [
{
id: '4',
name: 'demo4',
programParent: '2',
childs: [
{
id: '5',
name: 'demo5',
programParent: '4',
},
],
},
],
},
{
id: '3',
name: 'demo3',
programParent: '1',
},
],
},
{
id: '6',
name: 'demo6',
programParent: '',
},
]);
return (
<div>
<Tree data={data} />
</div>
);
}
Yes, with a recursive component:
const data = [
{
id: "1",
name: "demo1",
programParent: "",
childs: [
{
id: "2",
name: "dem2",
programParent: "1",
childs: [...]
},
...
]
},
...
];
export default function App() {
return <Node childs={data} name="root" />;
}
function Node({ childs, name }) {
return (
<div className="node">
<h2>{name}</h2>
{childs && childs.map((x) => <Node key={x.id} {...x} />)}
</div>
);
}
I would use a custom component for that demo
const Component = ({ item, level }) => {
const Heading = level <= 6 ? `h${level}` : "h6";
return (
<div>
<Heading>{item.name}</Heading>
{item.childs?.map((child) => (
<Component item={child} level={level + 1} />
))}
</div>
);
};
Usage
{data.length && data.map((item) => <Component item={item} level={1} />)}

Update nested Array Object Array in React State

I'm trying to update qty of product onClick event using useState in react, the data that I am updating is nested array-object-array
Below is the example of nested data I want to update the qty from it
let categoriesInfo = [
{
catid: 'category-1',
catName: 'Fun Stuff',
product: [
{
id : 1,
name: 'candy',
qty: 0,
},
{
id : 2,
name: 'cookie',
qty: 0,
}
]
},
{
catid: 'category-2',
catName: 'Fun Stuff2',
product: [
{
id : 1,
name: 'candy2',
qty: 0,
},
{
id : 2,
name: 'cookie2',
qty: 0,
}
]
}
]
I am using useState
const [productData, setProductData] = useState(categoriesInfo);
I am fetching the id and catid on click button from other component in the function x
const x = (data) =>{
console.log(productData)
const y = productData.map(obj => {
if (obj.catid == data.catid && obj.product[1-data.prodid].id == data.prodid) {
console.log(obj.product[1-data.prodid].name)
return {...obj.product[1-data.prodid], qty : 2}; //something like this
}
return obj;
});
setProductData(y);
}
Code looks really close, what about this?
const y = productData.map(obj => {
// you're not interested, just return obj
if (obj.catid !== data.catid) return obj;
// you are interested, return a new object
return {
...obj,
// iterate over it's products and update the one you want
product: obj.product.map(product => {
if(product.id !== data.prodid) return product
return { ...product, qty: 2}
})
}
});
Try like below:
let categoriesInfo = [ { catid: "category-1", catName: "Fun Stuff", product: [ { id: 1, name: "candy", qty: 0 }, { id: 2, name: "cookie", qty: 0 } ] }, { catid: "category-2", catName: "Fun Stuff2", product: [ { id: 1, name: "candy2", qty: 0 }, { id: 2, name: "cookie2", qty: 0 } ] } ];
function App() {
const [productData, setProductData] = React.useState(categoriesInfo);
const x = (data) => {
setProductData((prevProductData) =>
prevProductData.map((item) =>
item.catid === data.catid
? {
...item,
product: item.product.map((product) =>
product.id === data.prodid
? { ...product, qty: data.qty }
: product
)
}
: item
)
);
};
return (
<div>
<button onClick={() => x({ catid: "category-2", prodid: 2, qty: 4 })}>
Update value
</button>
<div>{JSON.stringify(productData, null, 4)}</div>
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>

Updating state array of objects from api call

Hy, let me explain my problem, i have a state of tag called tag_data :
const [tagData, setTagData] = useState([
{ key: '1', label: 'Music', active: 0 },
{ key: '2', label: 'Sport', active: 0 },
{ key: '3', label: 'Dance', active: 0 },
{ key: '4', label: 'Cook', active: 0},
{ key: '5', label: 'Video Games', active: 0},
{ key: '6', label: 'Travel', active: 0 },
{ key: '7', label: 'Picture', active: 0 },
{ key: '8', label: 'Animals', active: 0 },
{ key: '9', label: 'Coding', active: 0},
{ key: '10', label: 'Party', active: 0},
])
I do a api call for get ACTIVE tag from my user :
useEffect(() => {
const fetchData = async () => {
setLoad(true)
try {
const result = await axios.post('/user/activetag')
console.log(result.data.active_tag)
setTagData({
// update
})
} catch (error) {
console.log(error)
}
setLoad(false)
}
fetchData()
}, [])
Then the result store the active tags like this :
active_tag: Array(5)
0: {tag_id: 1, label: "Music"}
1: {tag_id: 2, label: "Sport"}
2: {tag_id: 3, label: "Dance"}
3: {tag_id: 4, label: "Cook"}
4: {tag_id: 5, label: "Video Games"}
I would like to update the tagData state and put active to 1 where the tag_id is equal to the key of tagData state, any idea ?
Full code :
import React, {useState, useEffect} from "react";
import { makeStyles } from '#material-ui/core/styles';
import Chip from '#material-ui/core/Chip';
import Paper from '#material-ui/core/Paper';
import DoneIcon from '#material-ui/icons/Done';
import axios from 'axios'
import Loading from '../../../../Loading/Loading'
const useStyles = makeStyles((theme) => ({
// style
})
export default function TagUser(){
const classes = useStyles();
const [load, setLoad] = useState(false)
const [tagData, setTagData] = useState([
{ key: '1', label: 'Music', active: 0 },
{ key: '2', label: 'Sport', active: 0 },
{ key: '3', label: 'Dance', active: 0 },
{ key: '4', label: 'Cook', active: 0},
{ key: '5', label: 'Video Games', active: 0},
{ key: '6', label: 'Travel', active: 0 },
{ key: '7', label: 'Picture', active: 0 },
{ key: '8', label: 'Animals', active: 0 },
{ key: '9', label: 'Coding', active: 0},
{ key: '10', label: 'Party', active: 0},
])
useEffect(() => {
const fetchData = async () => {
setLoad(true)
try {
const result = await axios.post('/user/activetag')
console.log(result.data)
setTagData({
// update
})
} catch (error) {
console.log(error)
}
setLoad(false)
}
fetchData()
}, [])
const handleDelete = (key) => {
//delete
}
const handleSubmit = (key) => {
//submit
}
if(load){
return <Loading/>
} else {
return(
<Paper variant="outlined" square component="span" className={classes.root}>
{
tagData.map((data) => {
if (data.active === 0) {
return (
<li key={data.key}>
<Chip
variant="outlined"
color="secondary"
label={data.label}
className={classes.chip}
onDelete={() => handleSubmit(data.key)}
deleteIcon={<DoneIcon />}
/>
</li>
)
} else {
return (
<li key={data.key}>
<Chip
color="secondary"
label={data.label}
className={classes.chip}
onDelete={() => handleDelete(data.key)}
/>
</li>
)
}
})
}
</Paper>
)
}
}
Disclosure: I am the author of the suspense-service library used in this answer.
If you're open to using a 3rd-party library, it can significantly simplify your data-fetching logic. You won't need a load state, or a useEffect(), the component will only render when the list is ready:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Chip from '#material-ui/core/Chip';
import Paper from '#material-ui/core/Paper';
import DoneIcon from '#material-ui/icons/Done';
import axios from 'axios';
import { createService, useService } from 'suspense-service';
import Loading from '../../../../Loading/Loading';
const defaultTags = [
{ key: '1', label: 'Music', active: 0 },
{ key: '2', label: 'Sport', active: 0 },
{ key: '3', label: 'Dance', active: 0 },
{ key: '4', label: 'Cook', active: 0},
{ key: '5', label: 'Video Games', active: 0},
{ key: '6', label: 'Travel', active: 0 },
{ key: '7', label: 'Picture', active: 0 },
{ key: '8', label: 'Animals', active: 0 },
{ key: '9', label: 'Coding', active: 0},
{ key: '10', label: 'Party', active: 0},
];
const UserActiveTags = createService(async (allTags) => {
try {
const result = await axios.post('/user/activetag');
console.log(result.data.active_tag);
const activeTags = result.data.active_tag.map((tag) => tag.tag_id);
const activeTagsSet = new Set(activeTags);
return allTags.map((tag) => ({
...tag,
active: activeTagsSet.has(tag.key) ? 1 : 0
}));
} catch (error) {
console.log(error);
return allTags;
}
});
export default function TagUser() {
return (
<UserActiveTags.Provider request={defaultTags} fallback={<Loading />}>
<TagList />
</UserActiveTags.Provider>
);
}
const useStyles = makeStyles((theme) => ({
// style
}));
function TagList() {
const { root, chip } = useStyles();
const tagData = useService(UserActiveTags);
const handleDelete = (key) => {
//delete
};
const handleSubmit = (key) => {
//submit
};
const tagList = tagData.map(({ active, key, label }) => {
const props = active === 0
? { variant: 'outlined', onDelete: () => handleSubmit(key), deleteIcon: <DoneIcon /> }
: { variant: 'default', onDelete: () => handleDelete(key) };
return (
<li key={key}>
<Chip
color="secondary"
label={label}
className={chip}
{...props}
/>
</li>
);
});
return (
<Paper variant="outlined" square={true} component="span" className={root}>
{tagList}
</Paper>
);
}
If you need tagData to be stateful, then
const tagData = useService(UserActiveTags);
needs to be updated to this:
const initialTagData = useService(UserActiveTags);
const [tagData, setTagData] = useState(initialTagData);
useEffect(() => {
setTagData(initialTagData);
}, [initialTagData]);
I think you could something like this,
In your useEffect(),
const result = await axios.post('/user/activetag');
const filteredTags = tagData.map((e) => {
const checkActive = result.data.some(i => i.tag_id == e.key);
if(checkActive){
const temp = {...e};
temp.active = 1;
return temp;
}
return e;
});
setTagData(filteredTags);
Hope that works!

How to replace refs in REACT.js (antd table example)

I am trying to apply this example to my own code, but it seems that "ref" properties are obsolete in this form. Can anyone help me with this code? Right now i am getting "Cannot read property 'focus' of undefined", when clicking on filter
const data = [{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
}, {
key: '2',
name: 'Joe Black',
age: 42,
address: 'London No. 1 Lake Park',
}, {
key: '3',
name: 'Jim Green',
age: 32,
address: 'Sidney No. 1 Lake Park',
}, {
key: '4',
name: 'Jim Red',
age: 32,
address: 'London No. 2 Lake Park',
}];
class App extends React.Component {
state = {
searchText: '',
};
handleSearch = (selectedKeys, confirm) => () => {
confirm();
this.setState({ searchText: selectedKeys[0] });
}
handleReset = clearFilters => () => {
clearFilters();
this.setState({ searchText: '' });
}
render() {
const columns = [{
title: 'Name',
dataIndex: 'name',
key: 'name',
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div className="custom-filter-dropdown">
<Input
ref={ele => this.searchInput = ele}
placeholder="Search name"
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={this.handleSearch(selectedKeys, confirm)}
/>
<Button type="primary" onClick={this.handleSearch(selectedKeys, confirm)}>Search</Button>
<Button onClick={this.handleReset(clearFilters)}>Reset</Button>
</div>
),
filterIcon: filtered => <Icon type="smile-o" style={{ color: filtered ? '#108ee9' : '#aaa' }} />,
onFilter: (value, record) => record.name.toLowerCase().includes(value.toLowerCase()),
onFilterDropdownVisibleChange: (visible) => {
if (visible) {
setTimeout(() => {
this.searchInput.focus();
});
}
},
render: (text) => {
const { searchText } = this.state;
return searchText ? (
<span>
{text.split(new RegExp(`(?<=${searchText})|(?=${searchText})`, 'i')).map((fragment, i) => (
fragment.toLowerCase() === searchText.toLowerCase()
? <span key={i} className="highlight">{fragment}</span> : fragment // eslint-disable-line
))}
</span>
) : text;
},
}, {
title: 'Age',
dataIndex: 'age',
key: 'age',
}, {
title: 'Address',
dataIndex: 'address',
key: 'address',
filters: [{
text: 'London',
value: 'London',
}, {
text: 'New York',
value: 'New York',
}],
onFilter: (value, record) => record.address.indexOf(value) === 0,
}];
return <Table columns={columns} dataSource={data} />;
}
}
ReactDOM.render(<App />, mountNode);
code that I am trying to execute
https://hastebin.com/yipusowala.coffeescript
{
title: 'Rider',
key: 'rider',
width: '25%',
dataIndex: 'rider.name',
filterDropdown: ({setSelectedKeys, selectedKeys, confirm, clearFilters}) => (
<div className="custom-filter-dropdown">
<Input
ref={(input) => { this.searchInput= input; }}
placeholder="Search name"
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={this.handleSearch(selectedKeys, confirm)}
/>
<Button type="primary" onClick={this.handleSearch(selectedKeys, confirm)}>Search</Button>
<Button onClick={this.handleReset(clearFilters)}>Reset</Button>
</div>
),
onFilter: (value, record) => record.rider.name.toLowerCase().includes(value.toLowerCase()),
onFilterDropdownVisibleChange: (visible) => {
if (visible) {
setTimeout(() => {
this.searchInput.focus();
});
}
},
render: (text) => {
const {userFilterText} = this.state.userFilterText;
return userFilterText ? (
<span>
{text.split(new RegExp(`(?<=${userFilterText})|(?=${userFilterText})`, 'i')).map((fragment, i) => (
fragment.toLowerCase() === userFilterText.toLowerCase()
? <span key={i} className="highlight">{fragment}</span> : fragment // eslint-disable-line
))}
</span>) : text;
}
},
Your code seems just fine
(apart from this object destructuring:
const {userFilterText} = this.state.userFilterText;
which I'm guessing is a typo)
I created this sandbox based on the example you described and the ref for the <Input /> component as well as the .focus() trigger - seem to be working fine. (check out the console and you can see the Input ref being logged)
Hope this helps :)

filtering array to remove item react

I'm trying to use filter to remove an object from the array. When I click on the recently added item it will console.log the items id but doesn't remove the item from the array, not sure where I'm going wrong?
import React, { Component } from 'react'
import { reduxForm } from 'redux-form'
// import Input from '../forms/Input/Input'
import actions from './actions'
import { connect } from 'react-redux'
import styles from './Catalogue.styl'
// import Checklist from './Checklist/Checklist'
#reduxForm({
form: 'orderReview',
})
#connect(null, actions)
export default class Catalogue extends Component {
constructor() {
super()
this.state = {
filterText: '',
favourites: [],
data: [
{ id: 1, label: 'baguettes' },
{ id: 2, label: 'bread' },
{ id: 3, label: 'potatoes' },
{ id: 4, label: 'rice' },
{ id: 5, label: 'pasta' },
{ id: 6, label: 'chicken' },
{ id: 7, label: 'beans' },
{ id: 8, label: 'apples' },
{ id: 9, label: 'oranges' },
{ id: 10, label: 'grapes' },
{ id: 11, label: 'biscuits' },
],
}
}
handleFilterUpdate = event => {
this.setState({
filterText: event.target.value,
})
}
addFavourite = (id) => {
const favList = this.state.favourites.concat([id])
this.setState({
favourites: favList,
})
console.log(id)
}
removeFavourite = (id) => {
console.log(id)
const removeFav = this.state.favourites.filter((_, i) => i !== id)
this.setState({
favourites: removeFav,
})
}
render() {
const {
data,
filterText,
favourites,
} = this.state
const NamesList = props => (
<div>
{props.data.filter(items => {
return items.label.toLowerCase().indexOf(filterText.toLowerCase()) >= 0
})
.map(item => {
return (
<div
key={item.id}
onClick={() => props.addFavourite(item.id)}
>
{item.label}
</div>
)
}
)
}
</div>
)
const SaveName = props => {
const idList = props.favourites.map(id => {
const { label } = data[id]
return (
<div>
<br />
<li key={id} onClick={() => props.removeFavourite(data[id])}>{label}</li>
</div>
)
})
return (
<div>{idList}</div>
)
}
return (
<div>
<div className={styles.filtersList}>
<ul className={styles.filtersUl}>
<li className={styles.filtersLi}>znacky</li>
<li className={styles.filtersLi}>zeme</li>
<li className={styles.filtersLi}>Specialni</li>
</ul>
</div>
<input
type="text"
value={filterText}
onChange={this.handleFilterUpdate}
placeholder="Hledat podle nazvu"
/>
<NamesList data={data} addFavourite={this.addFavourite}/>
{filterText}
<SaveName favourites={favourites} removeFavourite={this.removeFavourite} />
</div>
)
}
}
You are iterating through your entire array, and you compare the parameter id with the index of the currently processed item of the array.
Instead, compare the item.id with the parameter, not with i:
class MyApp extends React.Component {
constructor() {
super()
this.state = {
favourites: [
{ id: 1, label: 'baguettes' },
{ id: 2, label: 'bread' },
{ id: 3, label: 'potatoes' },
{ id: 4, label: 'rice' },
{ id: 5, label: 'pasta' },
{ id: 6, label: 'chicken' },
{ id: 7, label: 'beans' },
{ id: 8, label: 'apples' },
{ id: 9, label: 'oranges' },
{ id: 10, label: 'grapes' },
{ id: 11, label: 'biscuits' },
],
}
}
removeFavourite = (id) => {
const removeFav = this.state.favourites.slice();
removeFav.splice(id, 1);
this.setState({
favourites: removeFav
})
}
render() {
return(
<ul>
{this.state.favourites.map((item, i) => <li key={item.id}>{item.label} <button onClick={this.removeFavourite.bind(this, i)}>Remove</button></li>)}
</ul>
);
}
}
ReactDOM.render(<MyApp />, document.getElementById("myApp"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="myApp"></div>
Alternatively, you could also just use splice() to remove the item directly:
class MyApp extends React.Component {
constructor() {
super()
this.state = {
favourites: [
{ id: 1, label: 'baguettes' },
{ id: 2, label: 'bread' },
{ id: 3, label: 'potatoes' },
{ id: 4, label: 'rice' },
{ id: 5, label: 'pasta' },
{ id: 6, label: 'chicken' },
{ id: 7, label: 'beans' },
{ id: 8, label: 'apples' },
{ id: 9, label: 'oranges' },
{ id: 10, label: 'grapes' },
{ id: 11, label: 'biscuits' },
],
}
}
removeFavourite = (id) => {
const removeFav = this.state.favourites.filter(item => item.id-1 != id)
this.setState({
favourites: removeFav
})
}
render() {
return(
<ul>
{this.state.favourites.map((item, i) => <li key={item.id}>{item.label} <button onClick={this.removeFavourite.bind(this, i)}>Remove</button></li>)}
</ul>
);
}
}
ReactDOM.render(<MyApp />, document.getElementById("myApp"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="myApp"></div>

Categories

Resources