Find element and render on passing codition - arrays

I find names for some objects and have following source code:
const findAndRenderName = (projectId: number| undefined) => {
//i want to render here something when the condtion will pass
projectList?.map(project => projectId = project.id)
}
return (
<DetailsBox title={t('catalogPage.componentDetails.specs.used')}>
{
component?.projects.map(project => findAndRenderName(project.id))
}
</DetailsBox>
);
How to make kind of if from the map function, any idea?

I think what you're trying to accomplish is
projectList?.map(project => {
if(projectId === project.id){
// do something
}
})
of if you refer to the second map
component?.projects.map(project => {
if(findAndRenderName(project.id)){
// do something
}
})

Related

how to get length of filtered array react js

I try to display the number of cards even after it's filtered, but with this code I have only the initial number.
thanks in adavance
<div>{cards.length} Results<div>
{
cards.filter(card => {
if (card.title.toLowerCase().includes(search.toLowerCase())) {
return card;
}
})
.map((card, index) => {
return <CardJob key={index.id}
/>
})
}
Just do your filter before render then you'll have access to the length:
const filteredCards = cards.filter(card => card.title.toLowerCase().includes(search.toLowerCase()));
Then :
filteredCards.map(...
Or:
console.log(filteredCards.length);

React - Loop inside a loop not rendering

I have a map loop inside another loop like this:
{"undefined" !== typeof this.props.categoryObject['products'] && Object.keys(this.props.categoryObject['products']).length > 0 && Object.keys(this.props.categoryObject['products']).map(keyProd => {
const product = this.props.categoryObject['products'][keyProd];
if("undefined" !== typeof product) {
Object.keys(this.props.activeFilters).map(keyFilter => {
console.warn(this.props.activeFilters[keyFilter]);
return (<div>test</div>)
})
}
})}
The console works, but not the render. Any idea why ?
Thank you
The problem here that outer .map doesn't have return statement and your outer code doesn't have return statement too.
So you have to change your code to the following
return ("undefined" !== typeof this.props.categoryObject['products'] && Object.keys(this.props.categoryObject['products']).length > 0 && Object.keys(this.props.categoryObject['products']).map(keyProd => {
const product = this.props.categoryObject['products'][keyProd];
if("undefined" !== typeof product) {
return Object.keys(this.props.activeFilters).map(keyFilter => {
console.warn(this.props.activeFilters[keyFilter]);
return (<div>test</div>)
})
}
}))
Also some notes on how you can make your code more readable with new es6 features. Commented version
// It's better to extract products into separate variable
// as there are a lot of copy paste code for this action
const { products } = this.props.categoryObject;
// `undefined` is falsy value so you can just test next condition for early exit
if (!products) { return null; }
// 1. no need to test for `.length` as iterating empty array will make 0 iterations
// 2. use Object.entries you can immediately get key and value
return Object.entries(products).map(([key, product]) => {
// Same things as with `products` variable
if (product) {
// I think for your future code you can use `Object.entries` here too
return Object.keys(this.props.activeFilters).map(keyFilter => {
return (<div>test</div>)
})
}
})
Final version:
const { products } = this.props.categoryObject;
if (!products) { return null; }
return Object.entries(products).map(([key, product]) => {
if (product) {
return Object.keys(this.props.activeFilters).map(keyFilter => {
return (<div>test</div>)
})
}
})
NOTE to use all of them in all common browser you have to configure your babel properly

React - remove nested array item using setState function call

I am trying to remove a (semi) deeply nested item from an array using setState but it doesn't seem to be working. My state is structured as follows:
state = {
currentSeries: null,
currentRowIndex: null,
rows: [
{
id: shortid.generate(),
nodes: [],
series: [], // array with item I want to remove
},
],
};
and my remove item call:
onRemoveModelElementClick = (rowId, modelElementId) => {
this.setState((prevState) => {
const index = prevState.rows.findIndex(x => x.id === rowId);
const series = prevState.rows[index].series.filter(s => s.id !== modelElementId);
return series;
});
};
I tried spreading the remaining state is several ways but it does not seem to update properly. I the rowId and modelElementId are correct and I can verify they do filter the correct item out. I am just having trouble on what to return. I know it is something simple but for the life of me I can't see it.
My recommendation would be to use .map to make things are bit easier to digest. You can then write it like so:
onRemoveModelElementClick = (rowId, modelElementId) => {
const updatedRowsState = this.state.rows.map(row => {
// this is not the row you're looking for so return the original row
if (row.id !== rowId) {
return row;
}
const filteredSeries = row.series.filter(s => s.id !== modelElementId);
return {
// spread properties (id, node, series)
...row,
// overwrite series with item filtered out
series: filteredSeries,
};
});
// since rest of the state doesn't change, we only need to update rows property
this.setState('rows', updatedRowsState);
}
Hope this helps and let me know if you have any questions.
I think the issue here is how your code uses setState. The setState function must return an object. Assuming your filtering functions are correct as you describe, return an object to update the state:
return { series };
setState documentation
Here is what I did to get it working in case it can help someone else:
onRemoveModelElementClick = (rowId, modelElementId) => {
this.setState((prevState) => {
const updatedRowState = prevState.rows.map((row) => {
if (row.id !== rowId) {
return row;
}
const filteredSeries = row.series.filter(s => s.id !== modelElementId);
return {
...row,
series: filteredSeries,
};
});
return {
rows: updatedRowState,
};
});
};
All credit to Dom for the great idea and logic!

React.JS: Nested Filter/Map Arrays

I'm trying to learn React as part of a course I'm doing with Udacity. I've been battling this issue for a couple of days and can't seem to figure a way out of it.
Basically, I have an API call that returns an array of objects as a promise, I map or filter through these (I've tried both) and need to find the elements that already exist in an array booksOnShelves. I do this by comparing the .id property of each object. Once we find a match I need to set the .shelf property to the same value as the one in the existing Array and if the book doesn't exist I need to set its value to 'none'. All is good here but the problem is when I find a match the property updates the shelf to the correct one, but the iteration continues with the next book that obviously doesn't match and overwrites the .shelf value with none.
Here's the code for this particular method:
class SearchBar extends Component {
state = {
query: '',
result: []
}
getBooks = (query) => {
const booksOnShelves = this.props.books;
BooksAPI.search(query)
.then(res => {
if (res instanceof Array && res.length > 0) {
res.filter( searchedBooks => {
return booksOnShelves.filter( onShelves => {
if ( searchedBooks.id === onShelves.id) {
return searchedBooks.shelf = onShelves.shelf
} else {
return searchedBooks.shelf = 'none
}
})
})
this.setState({result: res.sort(sortBy('title'})
} else {
this.setState({result: []})
}
})
.catch( err => { console.log('ERROR: ', err)})
}
I've tried so many things but none was able to maintain the value of the shelf property.
Is there any way to stop the iteration from overwriting the matched value?
Any ideas how to achieve the intended outcome?
Thank you in advance for the help.
Should work fine in your case:
BooksAPI.search(query).then(res => {
if (res instanceof Array && res.length > 0) {
booksOnShelves.forEach((book) => {
const correspondingRes = res.find((item) => { return (item.id === book.id) });
if (correspondingRes) {
book.shelf = correspondingRes.shelf;
} else {
book.shelf = “none”;
}
});
}
Problem sorted with the help of all you guys I've made it work. Thanks a lot.
Just for reference here's the code that worked.
BooksAPI.search( query )
.then( res => {
if (res instanceof Array && res.length > 0) {
res.map( booksFromSearch => {
booksOnShelves.find( book => {
if( booksFromSearch.id === book.id) {
booksFromSearch.shelf = book.shelf
return booksFromSearch;
} else {
booksFromSearch.shelf = 'none'
}
})
})

ReactJS: Check if array contains value else append

I'm trying to check if a JSON response contains a value already inside an array and if it doesn't add it in. The problem I'm having is understanding how to approach this in reactjs. I'm checking before I append it but it doesn't want to work. I've tried passing in user object & user.id but these fail. The attempt below fails to compile but it should help understand what I'm trying to achieve.
Code:
componentWillMount() {
fetch('http://localhost:8090/v1/users')
.then(results => {
return results.json();
})
.then(data => {
data.map((user) => (
if(userList.hasOwnProperty(user.id)) {
userList.push({label: user.title, value: user.id})))
}
})
}
map return the resultant array, but you are not returning anything from it, you should instead use forEach Also you need to check if the userList array contains the id, for that you can use findIndex
What you need is
state = {
userList: [];
}
componentDidMount() {
fetch('http://localhost:8090/v1/users')
.then(results => {
return results.json();
})
.then(data => {
const newUserList = [...this.state.userList];
data.forEach((user) => { // use { here instead of
if(userList.findIndex(item => item.value === user.id) < 0) {
newData.push({label: user.title, value: user.id})
}
})
this.setState({userList: newUserList});
});
}
render() {
return (
{/* map over userList state and render it here */}
)
}
I'd recommend using reduce to turn the returned data into an array you'd like, then adding those values to your existing user list:
fetch('http://localhost:8090/v1/users')
.then(res => res.json())
.then(data => data.reduce((acc, user) => {
const idList = userList.map(user => user.id);
if (idList.indexOf(user.id) === -1) {
acc.push({label: user.title, value: user.id})
}
return acc;
},[]))
.then(newList => userList = [...userList, ...newList]);

Resources