Filtering Components on React Native - javascript

I'm trying to make a filtering checkbox list options to filter out the news to show on a feed. My app isn't yet getting information from database so I'm basically creating by hand to test the methods.
The variables I have are topics (which is a state prop), and feedNews, topics is an array with the topics that the user wishes to see in the feed, while feedNews are all the news components that exist to show in the feed.
e.g. of topics
this.state = {
topics: ['News-1','News-2','News-3']
}
e.g. of components for feedNews
const feedNews = [
{name:'News-1', comp: <FeedNews key={101} name="News-1" />},
{name:'News-2', comp: <FeedNews key={102} name="News-2" />},
{name:'News-3', comp: <FeedNews key={103} name="News-3" />},
{name:'News-1', comp: <FeedNews key={104} name="News-1" />},
{name:'News-3', comp: <FeedNews key={105} name="News-3" />}
]
Note: the keys on each component was just for a test
Basically what I have on my render of the class is calling a function that returns the filtered array of components:
filterFeedNews(){
let topics = this.state.topics;
return feedNews.filter((item) => {
return topics.indexOf(item.name)!==-1;
}).map(item => item.comp);
}
Now this function works everytime I open the app for the first time, but if I actually change the topics array with my filter options (list of checkboxes), sometimes there are options that disappear and they weren't the options that I had chosen. Btw, the update filter function is this:
updateFilter(newsName, value){
let newNewsTopics = this.state.topics;
if(value){
newNewsTopics.push(newsName);
}else{
newNewsTopics.splice(newNewsTopics.indexOf(newsName),1);
}
this.props.dispatch(setNewsFilter(newNewsTopics));
this.setState({
newsTopics: newNewsTopics,
});
}
this function is called by bind within each checkbox as action (because of the name of the props)
onClick(){
this.action(this.name, !this.state.value);
this.setState({
value: !this.state.value,
});
}
My question is, what am I doing wrong on those functions, or is it "normal" for this to happen in react-native
PS: if there's only one news per topic, there is no problem. This only doesn't work when there are more than one news per topic
UPDATE
I'm not sure if this is the problem, but if the problem is being ScrollView instead of ListView for filtering and rendering purposes
render(){
return (
<View style={styles.root}>
<Toolbar home={true} options={true} title='Feed' actionOptions={this.optionsAction.bind(this)}/>
<View style={styles.flexContainer}>
<ScrollView style={styles.flexContainer}>
{this.filterFeedNews()}
</ScrollView>
</View>
<View style={styles.spacing} />
{this.options()}
</View>
);
}
Solution
So basically the main wasn't even the filtering, the problem was more in terms of the rendering of the components. With the help of a colleague I had to change a bit the structure of what I posted above.
What changed:
const feedNews = [
{name:'News-1', ...otherProps},
{name:'News-2', ...otherProps},
{name:'News-3', ...otherProps},
{name:'News-1', ...otherProps},
{name:'News-3', ...otherProps}
];
added a dataSource to my state
dataSource: ds.cloneWithRows(feedNews),
my filter feed function was changed as well to adapt to the new way of thought
filterFeedNews(){
let topics = this.state.newsTopics;
let feed = feedNews.filter((item) => {
return topics.includes(item.name);
});
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.setState({dataSource: ds.cloneWithRows(feed)});
}
my update filter action had to be changed as well
updateFilter(newsName, value){
let newNewsTopics = this.state.topics;
if(value){
newNewsTopics.push(newsName);
}else{
newNewsTopics.splice(newNewsTopics.indexOf(newsName), 1);
}
this.props.dispatch(setNewsFilter(newNewsTopics));
this.setState({
newsTopics: newNewsTopics,
}, () => this.filterFeedNews());
}
and my render instead of the ScrollView it now has a ListView
<ListView
style={styles.flexContainer}
dataSource={this.state.dataSource}
removeClippedSubviews={false}
renderRow={(rowData, sectionID, rowID) => this.renderRow(rowData, sectionID, rowID)}
enableEmptySections={true}
/>
Pro: it doesn't have the problems I had with my previous approach
Con: LayoutAnimation that I used everytime the component is updated doesn't work with the ListView, so the user only has feedback of the filtration if the news in the feed have their pictures
Solution maintaining ScrollView
In case if I want to keep my initial approach with Scroll View, my solution was basically this
updateFilter(newsName, value){
let newNewsTopics = this.state.topics;
if(value){
newNewsTopics.push(newsName);
}else{
newNewsTopics.splice(newNewsTopics.indexOf(newsName), 1);
}
this.props.dispatch(setNewsFilter(newNewsTopics));
this.setState({
newsTopics: newNewsTopics,
});
}
filterFeedNews(){
let topics = this.state.topics;
let i = 0;
return feedNews.filter((item) => {
return topics.includes(item.name);
}).map((item) => {
return (<FeedNews key={++i} name={item.name}/>);
});
}
Where this.state.topics maintains the structure (an array of strings), whereas feedNews basically turns into an array of objects like in the example above for the previous solution, and then it's converted with the function filterFeedNews using filter and map o "convert" into an array of components.
In a way, the result is exactly as the same as ListView, the original animation that had isn't "working", but that's because of how the implementation is done.
Solution for the Animation
The problem I had that was causing all the problems I talked above was actually because of LayoutAnimation, everytime I "deleted" a news feed with the filtering options the Layout Animation ended up deleting more than the news feed from the specific category.
I apologize for this since I thought LayoutAnimation wasn't the problem and like that I didn't post that part of the code.
Basically for this deleting problem doesn't occur, for now the solution is to make this:
LayoutAnimation.configureNext({
duration: 300,
create: {
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.opacity,
},
update: { type: LayoutAnimation.Types.easeInEaseOut },
});
If you are asking why I didn't put the delete, that's because in LayouAnimation delete doesn't work well on Android, only on iOS
Again, sorry for wasting your time without putting all the information

If I am not mistaken, setState does not update the state in react immediately. So in order to prevent that, I would suggest you to call the function on the callback, like the following:
this.setState({
value: !this.state.value,
}, ()=> {
this.action(this.name, this.state.value);
});
Does that makes sense?

Related

How to set initial state value in Gatsby based on the result from static query?

I'm trying to make a video filtering UI. It will have a grid of videos and some filters in the sidebar. My videos are an array of items/objects that I get from a Gatsby static query.
One of my filters (from a material-ui Autocomplete component) generates an an array of tags, e.g ["data science", "javascript"]. I'm trying to filter the videos list down according to whether the tags in the filters match any of the video tags.
I'm not sure how to make this gatsby component stateful in the way I want to.
I want to be able to give my VideosGrid component all of the videos
on initial load (as there are no filters set)
I have the multichip component able to call setFilterTags
I'm try to use useEffect to listen for changes on the filterTags
and then trigger a state change and update the videos that get passed
to the videos grid component.
But I can't figure out how to make the gatsby data stateful. When I
tried, const [filteredItems, setfilteredItems] = useState([data.allItem.edges]); it breaks because my video grid
component doesn't have anything to load.
export default function LandingPage() {
const classes = useStyles();
const data = useStaticQuery(graphql`
query MainIndexQuery {
allItem(sort: {fields: view_count, order: DESC}) {
edges {
node {
title
tags
stuff
}
}
}
}
`);
const [filterTags, setFilterTags] = useState([]);
const [filteredItems, setfilteredItems] = useState([data.allItem.edges]);
// ```this doesn't seem to work.```;
// let filteredItems = data.allItem.edges; // this works
useEffect(() => {
filteredItems = filteredItems.filter(function (el) {
return el.node.tags.some((tag) => filterTags.includes(tag));
});
// I want to call setState here
}, [filterTags]);
// setFilterTags gets invoked by my chip filtering UI component...
return (
<>
<MultiChip setFilterTags={setFilterTags} />
<VideosGrid locations={filteredItems} />
</>
);
}
I think you want to use:
const [filteredItems, setfilteredItems] = useState(data.allItem.edges);
The edges (from data.allItem.edges) is an array of images itself so you don't need to wrap it.
In addition, to avoid mutation caveats, I will suggest cloning the state array of data. Something like this will create a shallow clone:
useEffect(() => {
let clonedArray= [...filteredItems];
filteredItems = clonedArray.filter(function (el) {
return el.node.tags.some((tag) => filterTags.includes(tag));
});
// I want to call setState here
}, [filterTags]);

Filter in react query not working properly on first attempt

I am trying to get only females from an array using a filter, but on the first attempt react query returns the whole array, after that it is working fine. Any idea what property I have to add or remove, so this side effect disappears.
Here is my code:
import React, { useState } from "react";
import { useQuery } from "react-query";
import getPersonsInfo from "../api/personCalls";
export default function Persons() {
const [persons, setPersons] = useState([]);
const { data: personData, status } = useQuery("personsData", getPersonsInfo, {
onSuccess: (data) => {
setPersons(data.data);
},
onError: (error) => {
console.log(error);
}
});
const getFemaleOnlyHandler = () => {
const result = personData.data.filter(
(person) => person.gender === "female"
);
setPersons(result);
};
return (
<>
<button onClick={getFemaleOnlyHandler}>Female only</button>
{status === "loading" ? (
<div>Loading ... </div>
) : (
<div>
{persons.map((person) => (
<div>
<p>{person.name}</p>
<p>{person.lastName}</p>
<p>{person.address}</p>
<p>{person.gender}</p>
<p>{person.country}</p>
<p>{person.city}</p>
</div>
))}
</div>
)}
</>
);
}
I added the full code in code sandbox: https://codesandbox.io/s/relaxed-drake-4juxg
I think you are making the mistake of copying data from react-query into local state. The idea is that react-query is the state manager, so the data returned by react-query is really all you need.
What you are experiencing in the codesandbox is probably just refetchOnWindowFocus. So you focus the window and click the button, react-query will do a background update and overwrite your local state. This is a direct result of the "copy" I just mentioned.
What you want to do is really just store the user selection, and calculate everything else on the fly, something like this:
const [femalesOnly, setFemalesOnly] = React.useState(false)
const { data: personData, status } = useQuery("personsData", getPersonsInfo, {
onError: (error) => {
console.log(error);
}
});
const getFemaleOnlyHandler = () => {
setFemalesOnly(true)
};
const persons = femalesOnly ? personData.data.filter(person => person.gender === "female") : personData.data
you can then display whatever you have in persons, which will always be up-to-date, even if a background update yields more persons. If the computation (the filtering) is expensive, you can also use useMemo to memoize it (compute it only when personData or femalesOnly changes - but this is likely a premature optimization.
I'm not totally familiar with react-query however the problem is likely that it is re-fetching (async!) everytime the component updates. Since setPersons() triggers an update (ie. sets state) it'll update the new persons state to be the filtered female list and then trigger a fetch of all persons again which comes back and sets the persons state back to the full list (ie. see what happens when you click the female filter button and then just leave it).
There is a more idiomatic way to achieve this in React which is to keep a "single source of truth" (ie. all the persons) and dynamically filter that based on some local ui state.
For example see below where data becomes the source of truth, and persons is a computed value out of that source of truth. This has the benefit that if your original data changes you don't have to manually (read: imperatively) update it to also be females only. This is the "unidirectional data flow" and "reactivity" people always talk about and, honestly, it's what makes React, React.
const { data = { data: [] }, status } = useQuery(
"personsData",
getPersonsInfo,
{
onSuccess: (data) => {},
onError: (error) => {
console.log(error);
}
}
);
const [doFilterFemale, setFilterFemale] = useState(false);
const persons = doFilterFemale
? data.data.filter((person) => person.gender === "female")
: data.data;
https://codesandbox.io/s/vigorous-nobel-9n117?file=/src/Persons/persons.jsx
This is ofc assuming you are always just loading from a json file. In a real application setting, given a backend you control, I would always recommend implementing filtering, sorting and pagination on the server side otherwise you are forced to over-fetch on the client.

Local storage in react todo list

I created to do list using react, but I want it to be local storage - so when the user refresh the page it still saved the items and will present them.
I read I need to use localStorage but I'm not sure where and how, attach the app.js and TodoItem component
class App extends Component {
state = {
items: [],
id: uuidv4(),
item: "",
editItem: false
};
handleChange = e => {
...
};
handleSubmit = e => {
e.preventDefault();
const newItem = {
id: this.state.id,
title: this.state.item
};
const updatedItems = [...this.state.items, newItem];
this.setState({
items: updatedItems,
item: "",
id: uuidv4(),
editItem: false
});
};
...
render() {
return (
<TodoInput
item={this.state.item}
handleChange={this.handleChange}
handleSubmit={this.handleSubmit}
editItem={this.state.editItem}
/>
<TodoList
items={this.state.items}
clearList={this.clearList}
handleDelete={this.handleDelete}
handleEdit={this.handleEdit}
/>
);
}
}
export default class TodoItem extends Component {
state = {
avatarURL: '',
}
componentDidMount() {
imgGen().then(avatarURL => this.setState({ avatarURL }));
}
render() {
const { title, handleDelete, handleEdit } = this.props;
const { avatarURL } = this.state;
return (
<h6>{title}</h6>
<span className="mx-2 text-success" onClick={handleEdit}>
</span>
<span className="mx-2 text-danger" onClick={handleDelete}>
</span>
);
}
}
You can do it like this, mind the comments
class App extends Component {
state = {
// load items while initializing
items: window.localStorage.getItem('items') ? JSON.parse(window.localStorage.getItem('items')) : [],
id: uuidv4(),
item: "",
editItem: false
};
handleChange = e => {
// ...
};
handleSubmit = e => {
e.preventDefault();
const newItem = {
id: this.state.id,
title: this.state.item
};
const updatedItems = [...this.state.items, newItem];
// Save items while changing
window.localStorage.setItem('items', JSON.stringify(updatedItems));
this.setState({
items: updatedItems,
item: "",
id: uuidv4(),
editItem: false
});
};
// ...
render() {
return (
<>
<TodoInput
item={this.state.item}
handleChange={this.handleChange}
handleSubmit={this.handleSubmit}
editItem={this.state.editItem}
/>
<TodoList
items={this.state.items}
clearList={this.clearList}
handleDelete={this.handleDelete}
handleEdit={this.handleEdit}
/>
</>
);
}
}
Here's some simple logic you can use in your componentDidMount() method of your App.
const localStorageList = localStorage.getItem('todo-list')
if (!localStorageList) {return null} else {this.setState({items: localStorageList})
To add to the localStorage please look at this question
and this resource
Let me help you with this, using the least no. of codes. I have written a clear explanation of the steps, for you all to better understand, please bear with me , it is definitely with the time to read.
Also, note this solution is perfectly crafted for functional components. However I have mentioned how to do it in class components, you have to tweak some things if you are using class components. Like you can not use hooks in class-based components, but access this instance, so it will be fine, either ways
Please give it a full read, if you are having a tough time understanding the functionality, I have tried to break down the process in layman. The explanation is long, the lines of code is just under 10. happy to help
Persisting states of the todo app, upon page refresh, is pretty simple.
We can use State management libraries for it, or local storage as well.
Here, we will just go with the most simple one - using local storage.
Before we jump to the code, let us build the functionality visually.
So, after the user enters things in the todo space, we want few things to happen:
We want to store the list of items (which will essentially be an array) in the local storage. (We can skip the JSON.parse, here, since the array that will be saved, will be string, bcz user enters string in the todo-app, generally, however, it's not a bad idea to parse the userinputs).
useEffect(()=>{
window.localStorage.setItems("key" , value)
}, [dependency])
After you do this, make sure you check the dev-tools => application => localStorage => to see if the key and values are being stored. You shall be able to see them.
However, you will notice, that upon refresh, the localStorage values stay, but the data in the UI are lost. Not surprising.
This is the last and important step.
What we want upon page reload? Let us break it down :
We want to check if there is any data that is there in the localStorage. If there is: we will change the state of the app, based on the previous user inputs.
If there is no data in the LocalStorage, we will just pass an empty array.
Using hooks, in the functional component is actually What I prefer, class components require many boiler plates, so, the code...
import {useState} from 'react';/for functional components
//for class components you can just init the state , in the constructor(props) and
change it using the this.setState method
//to getItems from localStorage to render in the UI
useEffect(()=>{
const storedData = localStorage,getItems("keys" , value)
storedData ? setValue(value) : [];
},[])
[] : because we want it to render on every reload, once.
smake sure to initiliaze the state using useState;
const [value , setValue] = useState("")
//to setItems in localStorage
useEffect(()=>{
window.localStorage.setItems("key" , value)
}, [dependency])
useEffect is essentially a hook for functional components which is similar to componentDidMount in-class components.
If using class components, instead of using the useState, hook, use this.setState.
You could format your todolist into a JSON string and store it using :
localStorage.setItem("todolist", "your_JSON_string_here");
However, web Local Storage have storage limitations which will cause issues if the data stored are getting larger in time.
More info at here
Perhaps you could consider IndexedDB (if you are storing huge data) INFO

React app - Load selected array in Material UI Table not rendering checks

So I have been working hard for days and searching on how to do this. I have a Material UI table in my React App. I want to load a table where if my user has entries in the selected array it will prerender the checks in the DOM. The selected array is populated with the entries I want but my table which uses a onClick I think needs an event to trigger the DOM to render the check. This is relevant part of my table body.
<TableBody>
{this.props.competitorData.map(competitor => {
const isSelected = this.props.isSelected(competitor.key);
return (
<TableRow
hover
onClick={() => this.props.handleClick(competitor)}
role="checkbox"
aria-checked={isSelected}
tabIndex={-1}
key={competitor.key}
selected={isSelected}
>
<TableCell padding="checkbox">
<Checkbox checked={isSelected} />
</TableCell>
I have a toggle that loads my table. It fills the selected the array with the subset of data I want trigger in componentWillMount. (it's 2 tables, tier1 and tier 2).
componentWillMount() {
this.renderChecks(this.props.team)
}
renderChecks(team) {
const { selected1 } = this.state;
const { selected2 } = this.state;
let newSelected1 = [];
let newSelected2 = [];
team.map(teammate => {
if (teammate.tier === "1") {
newSelected1 = newSelected1.concat(selected1, teammate.key)
} else if (teammate.tier === "2") {
newSelected2 = newSelected2.concat(selected2, teammate.key)
}
this.setState({ selected1: newSelected1 });
this.setState({ selected2: newSelected2 });
})
}
Essentially I need a way to render isSelected based of another list that is the smaller list (team is a subset of competitorData) that has the same keys. Ive tried so many things it's to many to list here. Im looking for help on what to do to make this work because nothing has worked and Im not sure what direction I should be going on in at this point. I've tried a lot of things that seem to cause instability in the render. Essentially I've tried to make the isSelected more state based but setting and resetting that state with inline functions like
{() => this.myFunctionThatUpdatesIsSelectedState(Key)}
These blow up in render. Sometimes cause an ugly infinite loop.
Update
Based on #Eld0w post below this does render my subset of checks.
checkKeys(val) {
return this.props.team.some(teammate => {
return val.key === teammate.competitorKey;
});
}
getCompetitors = () => {
const { competitorData, team } = this.props;
return competitorData.map(
value => ({
value,
isSelected: this.checkKeys(value)
})
)
}
Tables looks like this now.
<TableBody>
{this.getCompetitors().map(competitor => {
console.log('MYCOMPETITOR2::', competitor);
return (
<TableRow
hover
onClick={event => this.props.handleClick(event, competitor.value)}
role="checkbox"
aria-checked={competitor.isSelected}
tabIndex={-1}
key={competitor.value.key}
selected={competitor.isSelected}
>
<TableCell padding="checkbox">
<Checkbox checked={competitor.isSelected} />
</TableCell>
There is small issues I didn't see coming. Now my table renders only the preselected checks since im not using my previous isSelected function which was:
isSelected1 = key => this.state.selected1.indexOf(key) !== -1;
Basically i need to render the existing checks but maintain the standard isSelected function somewhere in the process as well. If I think of something or post anything about it I'll update here as well. Further input is obviously welcome.
I think i need to load my team into my selected array then run my standard isSelected function. But this is where I seem to run into trouble since that is state based. Render goes crazy on me.
Final Update
So it was late last night. I just needed to change the criterion to make this whole thing work. I load my team array in the local state selected array. Then performed isSelected property check on my competitor. Now it loads my preselected and the user can then edit selects in the table from that point.
Final Solution
Load the preselect team into the local selected state array.
componentWillMount() {
this.renderChecks(this.props.team);
}
I have tiered tables. That is just some business logic (not important here). teammate.competitorKey is the key I store that is same key as the larger table, which is competitorData. I need that to get the compares to work.
renderChecks(team) {
const { selected } = this.state;
let newSelected = [];
team.map(teammate => {
if (teammate.tier === '1') {
newSelected = newSelected.concat(selected, teammate.competitorKey)
this.setState({ selected: newSelected });
}
})
}
getCompetitor can now just verify the value key exist in the array using includes
getCompetitors = () => {
const { competitorData, team } = this.props;
console.log('THISSTATESELECTED:::', this.state.selected)
return competitorData.map(
value => ({
value,
isSelected: this.state.selected.includes(value.key)
})
)
}
And Final Table looks like
<TableBody>
{this.getCompetitors().map(competitor => {
return (
<TableRow
hover
onClick={event => this.handleClick(event, competitor.value)}
role="checkbox"
aria-checked={competitor.isSelected}
tabIndex={-1}
key={competitor.value.key}
selected={competitor.isSelected}
>
<TableCell padding="checkbox">
<Checkbox checked={competitor.isSelected} />
</TableCell>
I know this is a lot of writing but is spent a lot of time trying to get all this working. I hope it helps someone looking to do. I will look into making this more redux worth and possibly going the reselect route to optimize but for now im going to enjoy a working table for a day. Thank you again #Eld0w !!
So basically, you want to add an isSelected props to your competitors array depending on another array's values. Avoid using state, it's only props combinations.
The straightforward solution
Instead of mapping directly your competitor's array, map on a function returning an array.
getCompetitors = () => {
const { competitors, team } = this.props;
return competitors.map(
competitor => ({
...competitor,
isSelected: // criterion
})
)
}
Basically, what this does is destructuring the object and adding a new property isSelected thanks to the spread operator ... (ES6)
In your render then call this.getCompetitors().map(competitor => ...) instead of this.props.competitors.
Optimize this solution
You will want to use a plugin such as reselect to avoid any useless render operation.
const competitorSelector = createSelector(
props => props.competitors,
props => props.team,
(competitors, team) => competitors.map(
competitor => ({
...competitor,
isSelected: // criterion
})
)
)
and then use it like this in your render :
this.competitorSelector(this.props)
You will also need to use competitor.isSelected instead of isSelected since the property is now part of your competitor's properties.

Simple Add / Remove Component Pattern

I'm quite confused about this pattern in React. I have seen it in other places it but it does not seem correct.
Given the below code:
/** #jsx React.DOM */
var React = window.React = require('react'),
Item = require("./ui/Item");
var ItemApp = React.createClass({
getInitialState: function() {
return {
items: [ "Example Item" ] // we want one thing to render initially
}; // so prepopulate with one thing
},
getDefaultProps: function () {
return {
index: 1
}
},
onAddItem: function (e) {
var debts = this.state.debts.push( "New Item " + this.props.index);
this.setState({ items: this.state.items });
this.props.index++;
},
onRemoveItem: function (i) {
// splice here
this.state.items.splice(i, 1);
this.setState({ items: this.state.items });
this.props.index--;
},
render: function () {
var items = this.state.items;
var closeFn = this.onRemoveItem;
return (
<div className="col-lg-12">
<div className="cold-md-3"></div>
<div className="col-md-3 col-md-offset-9">
<button type="button" className="btn btn-default" onClick={this.onAddItem}><span className="glyphicon glyphicon-plus"></span> Add New Debt</button>
</div>
{items.map(function (item, i) {
return <Item name={item} closeFn={closeFn.bind(null, i)} key={i} />;
})}
</div>
);
}
});
The example above works like intended (it's a list and you can add and remove things at will) however whenever I add something renders the whole thing over again.
So after only adding one component the whole thing has rendered 3 times. After clicking twice it will have rendered 5 times. You can see why this might be a problem.
This seems really inefficient is there a better way to do this?
If you want to manually manage the dom, react probably isn't for you. You can always do it better than the abstraction if you really want to.
In react, it's usually best to aim for code that can clearly express its intent to react, and let it do its thing.
You code is close, the only problem is your key attributes don't uniquely reflect the items in the array. Index based keys are 100% fine for when you have a stack. I gave a more detailed answer to a similar question.
To actually solve this here, because any item can be removed at any time, you need to encode a unique identifier in the item itself. Instead of storing an array of strings ["a", "b", "c"] you should store an array of objects [{id: '1', text: "a"}, {id: '2', text: "b"}, {id: '3', text: "c"}]. You can then use the id as your key and it'll be more efficient.
This is unrelated to the question, but this.props.index-- is modifying props, which is bad and unreliable. If you need to keep a counter for some reason, set it directly on this in componentWillMount. If you need to communicate something up the tree, you accept a callback as a prop, and call that.
Also <Item name={item} closeFn={closeFn.bind(null, i)} key={i} /> doesn't describe any way to get data back out of the Item, other than when deletion is requested.

Categories

Resources