Looping through an array to generate a component(undefined array) - reactjs

I've got the following object, and trying to loop through the list:
const [object, setObject] = useState({
answer: {
[29]: {
list: [],
},
},
});
Now I've got a separate function to loop through the list further down the code, but somehow getting 'undefined' when the page tries to load initially.
const List = object["answer"][29]["list"].map(
(item, index) => (
<div> {item.name} </div>
...etc
)
)
Not sure what I'm missing here. Any help is appreciated! Thanks!

You can use the optional chaining operators when working with arrays.
object?.["answer"]?.[29]?.["list"]?.map(...)
This way it should not crash if the value is not set when loading.

Related

React search and filter: TypeError: setFilterFn is not a function

I'm working on a search and filter function. When I type text into the search box, the content that matches the criteria will be filtered out. I want to use the following function to achieve this, but when I type, the "TypeError: setFilterFn is not a function" will occur.
I don't know where goes wrong, How should I fix it?
Thx a lot!
const [setFilterFn] = useState({ fn: items => { return items; } })
const handleSearch = e => {
let target = e.target;
setFilterFn({
fn: items => {
if (target.value != "")
return items;
else
return items.filter(item => item.fullName.toLowerCase().includes(target.value.toLowerCase()))
}
})
}
The quick fix... add a comma ...
const [,setFilterFn] = useState((items) => ( items));
it also looks as if you may have an issue with your logic..
if (target.value != "")
The operator here should probably be === otherwise you will only filter for blank strings.
Take a look at useState function, that function returning array with two arguments, first value of state , the second is callback function which will change your satate value. You are providing only one value, so react assuming that is value not a function. You can read more in docs

Reactjs array map mutation

I have come around this topic today.
I am trying to map an array and update it like this.
const editTask = (id, newTitle) => {
const updatedTodo = [...tasks].map(task => {
task.id === id ? {...task, title: newTitle} : task
});
setTasks(updatedTodo);
};
tasks is array of objects
One of my friends have told me that there is no need to copy the original array during map. because map itself returns the new array.
But as far as I know this array is considered as 2 level deep array and it needs to copy the original array too for the update of the object.
Can someone explain to me which way is correct and which is not? I am lost.
Thanks in advance
Your friend is right: map DOES return a new array (unlike forEach)
Since you're using react-hooks, creating a new array for the updated tasks is considered redundant and the best way to achieve the same result is to do something like this:
const editTask = (id, newTitle) => {
setTasks((tasks) =>
tasks.map((task) => (task.id === id ? { ...task, title: newTitle } : task))
);
};

Printing data from array using shorthand

I am using react-admin framework and I am trying to print data from my array.
My array is looking like this:
enter image description here
As you can see it currently has 3 indexes. Each of them stores different data. I want to print these data on to same page.
I am aware that I need to use some sort of cycle (for, foreach), but I really dont know how to implement it in shorthand.
This is my code, that I need to loop:
ID: {this.state.source[index].Id}<br></br>
AuditDate: {this.state.source[index].AuditDate}<br></br>
UserId: {this.state.source[index].UserId}<br></br>
Resource: {this.state.source[index].EntitySet}<br></br>
Entity1: {this.state.source[index].Entity1}<br></br>
Entity2: {this.state.source[index].Entity2}<br></br>
Operation: {this.state.source[index].Operation}<br></br>
EndPoint: {this.state.source[index].EndPoint}<br></br>
Changes: {this.state.source[index].Changes}<br></br>
Any ideas how to loop this?
Thank you in advance
You can make use of map to iterate over array,
{
this.state.source && this.state.source.length > 0 && this.state.source.map(source => {
return <>
<div>ID: {source.Id}</div>
<div>AuditDate: {source.AuditDate}</div>
<div>UserId: {source.UserId}</div>
<div>Resource: {source.EntitySet}</div>
<div>Entity1: {source.Entity1}</div>
<div>Entity2: {source.Entity2}</div>
<div>Operation: {source.Operation}</div>
<div>EndPoint: {source.EndPoint}</div>
<div>Changes: {source.Changes}</div>
</>
})
}
renderSources() {
const sources = source.map((eachSource) => {
return (
<div>
<span>`ID: ${eachSource.Id}`</span>
<span>`AuditDate: ${eachSource.AuditDate}`</span>
<span>`UserId: ${eachSource.UserId}`</span>
<span>`Resource: ${eachSource.EntitySet}`</span>
<span>`Entity1: ${eachSource.Entity1}`</span>
<span>`Entity2: ${eachSource.Entity2}`</span>
<span>`Operation: ${eachSource.Operation}`</span>
<span>`EndPoint: ${eachSource.EndPoint}`</span>
<span>`Changes: ${eachSource.Changes}`</span>
</div>
);
});
return sources;
}
render() {
return (<div>{this.renderSources()}</div>);
}

How do I flatten the array and remove empty arrays from results of combineLatest(...)?

I’m working in an angular 6 application. I have a function that returns an observable of an array of observables, which in turn are observables of arrays.
The results might look something like this:
[
[],
[],
[object, object],
[],
[object],
[],
[object, object, object],
[]
]
As you can see, it’s an array of arrays and some arrays might be empty.
I’d like to list each object in each inner array on the page as follows:
<div *ngFor="let watcher of InvitationService.getInvitations() | async">
<div *ngFor="let invitation of watcher">
{{ invitation | json }}
</div>
</div>
And getInvitations() looks like this:
getInvitations() {
const groupedInvitations$: Observable<any>[] = [];
groups.forEach(group => {
const groupInvites$ = this._firestoreService.collection(`GroupInvitations/${group.groupID}/Invites`);
groupedInvitations$.push(groupInvites$);
});
Return Observable.combineLatest(groupedInvitations$);
}
What I’d like to do is remove the empty arrays from the results returned from combineLatest(…) and flatten the rest into a single one dimensional array.
I understand one can do this by piping through map(…) or flatMap(…) or things like that. But I’ve been trying things like that and nothing’s been working.
For example, I’ve tried this:
Return Observable.combineLatest(groupedInvitations$).pipe(
map(item => {
console.log(item);
});
);
But nothing gets logged to the console.
How can I flatten the array and remove empty arrays? Thanks.
Try using a filter first to remove the empty arrays and the use combineLatest to put them all together.
combineLatest(
groupedInvitations$.pipe(
filter(item => item.length > 0)
)
).pipe(
tap(item => { // Should be an array of arrays
console.log(item);
});
);
as I see it you can put an if condition before this line
groupedInvitations$.push(groupInvites$);
to check if the array length is greater than zero if yes add it to the returned array if not go to the next one
hope that helps

Replacing a single value in array stored in state with user input --Reactjs

I am creating a react madlibs app, and I want to update this.state.blanks array one item at a time when the user inputs words. I think I must be having trouble binding(but I thought having the fat arrow function bound it)? or I've just approached the problem the wrong way.
with my code the way it is now, I consistently get the error "cannot read property 'value' of undefined" (referring to the e.target.value in the handleEnterWord function)
here is what the problematic section of my code looks like right now.
state = {
error: null,
isLoaded: false,
title: null,
blanks: [noun, adjective, verb, etc],
value: [],
filledBlanks: []
};
handleEnterWord = (e, index) => {
const word = e.target.value
const newBlanks = [...this.state.blanks]
newBlanks[index] = word
this.setState({blanks: newBlanks})
console.log(word, newBlanks)
}
render() {
return (
<div className="App">
<button onClick = {this.handleNewMadlib}>New MadLib</button>
<h1>{this.state.title}</h1>
{this.state.blanks.map((blank, key) => {
return <input key={key} placeholder={blank} onChange={()=>this.handleEnterWord(e, key)}/>
})}
EDIT: I have added some values to the blanks array because I thought the question was a little ambiguous--this will be filled in by an API call in the actual app
Any help/advice at all is welcome.
thanks in advance :)
I believe your problem is in
onChange={()=>this.handleEnterWord(e, key)}
You should pass the event to the function like this
onChange={(e)=>this.handleEnterWord(e, key)}

Resources