State object.map() returning error - what am I overlooking? - reactjs

I would appreciate a second pair of eyes on this...
The React Component is reading-in data from MariaDB within a useEffect(). The data is being read-in without error and a console.log displays the correct data (see image below). In the return() section of the FunctionalComponent, I have this code:
<div class={style.tblBody}>
{tableData !== undefined &&
tableData.map((row: RDPresData) => {
return `<div>${row.title}</div>`;
})}
</div>
Here is the console error I receive (note the logged data above the red error).
I'm sure that at 3:30am I am missing something obvious...

Looking at your console.log output you can tell that tableData is an object, not an array. It says:
{tableData: {...}}
If it was an array, it would say:
{tableData: [...]}
For some reason, the tableData object happens to have numerical keys, like an array, but since it's not actually an array, .map doesn't exist.

If you do console.log(tableData) get above result. So you should get correctly object tableData and parse it to array to use map. Because map function is working for array.
Your tableData is an object. You should get values before use map.
<div class={style.tblBody}>
{tableData?.tableData !== undefined &&
Object.values(tableData.tableData).map((row: RDPresData) => {
return `<div>${row.title}</div>`;
})}
</div>

Related

How to access the data inside this object in react?

IN this image I have to fetch the data in the name key how to do it
i think this post will help you:
https://stackoverflow.com/questions/71936347/reactjs-how-can-i-access-data-from-nested-object-fetched-api/71936484#71936484
you can use map like a previos post then go through all the elements.
you can do like:
{Object?.map(o=>(
<div key={o.id}>
<h1>{o.name}</h1>
<h1>{o.address}</h1>
</div>
))}
Since the 'data' is an object, you can try this:
data['0'].name
If you want to get 'name' of all values in an array, you can try this:
Object.values(data).map(v => v.name)
This article might help.
https://www.digitalocean.com/community/tutorials/4-uses-of-javascripts-arraymap-you-should-know
Basically, you need to iterate/map through the items in the object.
Array.map((item) => {}))

How to render values from object with arrays in react typescript

Hey everyone I am trying to render a few values inside an object with arrays but have a hard to doing so.
Here is an example of the object:
test {
arr1: [{alert: "this is alert 1", passed: true}],
arr2: [{alert: "this is alert 2", passed: false}],
arr3: [{alert: "this is alert 3", passed: true}]
}
So basically I want to render the alert and passed values. I tried using Object.keys and then inside mapping individual array based on the key but no luck.
Edit: Sorry if I my question wasn't clear but I was able to resolve it. Here is the code for anyone curious.
Object.keys(this.state.test).map((name, I) => (
this.state.test[name].map((tmp, idx) => (
<li key={idx}>{tmp.alert}</li>
<li key={idx}>{tmp.passed}</li>
))
))
The object is called Object, not Objects. Any browser console or build process would be telling you that Objects is not defined.
Additionally, you can't have multiple JSX nodes that aren't surrounded by a parent node. So that's a syntax error in the callback passed to .map(). Which should also be evident as a console error or build error, depending on how you run your application.
Either way, these errors are being reported to you somewhere. If you're not seeing them then now is a good time to take a step back and better understand your development process, because seeing error messages when things fail is critical.
Once these two things are corrected, your logic works just fine:
Object.keys(this.state.test).map((name, I) => (
this.state.test[name].map((tmp, idx) => (
<>
<li key={idx}>{tmp.alert}</li>
<li key={idx}>{tmp.passed}</li>
</>
))
))
Though you may want to re-think your approach a bit, because using the same key value for multiple nodes isn't going to make React happy. It's unlikely to cause any immediate problems, though may produce warnings/errors in the browser console. But you'd be better off changing the markup a bit to just use a single <li> and modify how you're displaying the two values within that element.

Svelte make {:then} value of {#await} statement reactive

I have to make an api call and then display the data (an array). I want to sort the array, but the displayed data is not updated. I suppose this is because my data is not a reactive variable? How can I make my each loop rerun when data changes?
My code (simplified):
{#await promise} // api call
<p>Loading</p>
{:then data}
<button on:click={() => data.sort()}>sort data</button> // does not work
{#each data as student}
<p>{student.firstname}</p>
{/each}
{/await}
data is a reactive variable. The presence of a promise is unrelated to the issue: this occurs even if data is a normal variable. The issue is that Svelte doesn't properly pick up that a change occurred to data when you click the button. You can force Svelte to pick up the changes by explictly assigning to data.
The other issue is that you can't sort objects without providing a custom sort function to sort based on a key of the object. .sort((a, b) => a.firstname.localeCompare(b.firstname)) sorts based on the firstname property of the objects.
Putting that together gives us:
<button on:click={() => data = data.sort((a, b) => a.firstname.localeCompare(b.firstname))}>sort data</button>

React json check if empty?

I'm making my last project for school. I want to check for if "{item.fields.haaksoort}" is empty. When this is empty I want nothing to happen. Else post "<p>haaksoort: {item.fields.haaksoort}</p>".
Sidenote: I can display "<p>haaksoort: {item.fields.haaksoort}</p>" and the connection is right.
You can use this pattern to check for empty variables. If the field has a value then your <p> will render. If haaksort doesn't exist on item.fields or the value of haaksort is undefined then the <p> won't render.
{item.fields.haaksoort && (<p>haaksoort: {item.fields.haaksoort}</p>)}
A couple of notes on this though:
item and fields must also exist.
This will not yield the desired result if haaksoort is the empty string
If you need to do checking on the above conditions then a middleware function like mentioned in the question comment will best serve you. Then you can do something like this in your render code:
{isEmpty(item.fields.haaksoort) ? '' : (<p>haaksoort: {item.fields.haaksoort}</p>)
Note that this is a simplistic example of a call to a middleware function that assumes that item exists with a property fields that also exists.
We can use the below function to check obj is empty. Here what
Object.keys
does is that, it returns the keys of the objects attributes, so if the length of the keys is 0 we can deduce that the object is empty.
function checkIfJSONisEmpty(obj){
return Object.keys(obj).length === 0;
}

Why does ternary in conditional class logic not provide the correct value?

I have a conditional class that should return the class name when true but it does not, even when true is returned. (I believe) This is due to the giant array of 40000 units I'm using to render a graph.
Fiddle
In the fiddle I want the class to be added to boxes 100, 101, and 102 on click. This should change the color.
This approach is a follow-up to another question that works in theory, but is not working in practice due to size of the array. I know this is absurd to have an array this large rendering a grid like this, but I'm invested and want to fix this. (But I'm open to other suggestions)
I want the below to add the class to some of the instances of the graph of 40000. When i matches and array of the boxes that should change color.
i is looping through 1...40000 while rendering a graph.
let indexes = [100,101,102]
<div className={'box ${indexes.includes(i) ? 'background-color' : 'null'}'}>
typeof(indexes.includes(i)) will be a Boolean.
I can see that true is returned and yet the class does not get added. However, if I try with a smaller array it works, so it seems it is a timing issue. setTimeout does not work here and causes the re-render to fail entirely.
The expected output should be, on document.querySelector('.box-container:nth-of-type(100'), 101, 102:
<div className='box background-color'></div>
But it is:
<div className='box null'></div>
Below is working example with some additional 'best practices' and corrections that will make you code more performant and readable...
https://jsfiddle.net/cantuket3/3cs7abyg/9/
(Oops, I provided a link to you example by accident initially. This one works)
(Also, I removed the inline snippets that were here a minute ago. The formatting that editor produced was completely illegible. Refer to jsFiddle above.)
You should move as much logic out of the render function as possible because every time React detects changes to state (which modify the UI) it will run the render function again. Also, makes your code more modular and readable...
render(){
return(
this.props.toRender.map(num => {
return <React.Fragment key={Math.random()}>
{this.renderBoxes(num)}
</React.Fragment>
})
)
}
TO
render(){
if (this.props.toRender && this.props.toRender.length) {
return(
<React.Fragment>
{this.renderBoxes()}
</React.Fragment>
)
} else {
return (
<div>
No Boxes yet!
</div>
)
}
}
This is unnecessary if you are defining this array imperativel. Just drop in the elements directly...
arr.push(100)
arr.push(101)
arr.push(102)
this.setState({
classesToAdd: arr
})
TO
this.setState({
classesToAdd: [10,11,12]
})
React only needs a 'key' when there a series of sibling elements, so it can optimize change detection.
<button key={Math.random()} onClick={this.updateState.bind(this)}>Add Classes</button>
TO
<button onClick={this.clickToAdd.bind(this)}>Add Class</button>

Resources