Creating a table in react using multiple component calls not working - javascript

I am trying to create a dynamic table of a sudoku app I am working on but I am unable to see why this code wouldnt work.
my base app passes in a ref hook and sends the 9x9 array to the Grid component
return(
<Grid arr={sudokuBoard.current.board} />
)
Then in my grid app, it makes a call to the RowComponent using the array.map function
export default function Grid(props){
let sudokuArray = props.arr;
return(
<table>
{sudokuArray.map((row, ind)=> {
<RowComponent setkey={ind} rowval={row} />
})
}
</table>
)
}
Which then calls a tablecell generation function
export default function RowComponent(props){
return(
<tr key={props.setkey}>
{props.rowval.map((item,ind) => {
<TableItem keyval={item} value={item}/>
})}
</tr>
)
}
And the table cell generating component looks like this
export default function TableItem(props){
let tableValue = props.value
console.log(tableValue)
return(
<td>{props.value}</td>
)
}
Any pointers on what could be going wrong? The array gets passed into Grid just fine, but its in the chained calls where things stop working.
Thanks

In react/JSX you have to use ( ) around your code block inside the map, instead of { }. Like this:
{sudokuArray.map((row, ind)=> (
<RowComponent setkey={ind} rowval={row} />
))}
{props.rowval.map((item,ind) => (
<TableItem keyval={item} value={item}/>
))}
Difference between {} and () with .map with Reactjs this is an answer that explains why.

Related

OnClick event with return in function, doesn't work in react js

I have a problem when I tried to load a table component with json data. I have a form as it is in the image below. The problem is at the button onClick event. Seems that when I click the button, nothing happen.
import '../css/customButton.css';
import '../css/customDropDownButton.css';
import '../css/customBoxContainer.css';
import '../css/customTableComponent.css';
import CustomTextbox from '../components/CustomFormTextBoxContainer.tsx';
import CustomButton from '../components/CustomButtonContainer.tsx';
import CustomPersonDropDownButton from '../components/CustomDropDownButton.tsx';
import JsonData from '../data/personType.json'
import {RegistrationTableHeader} from '../enums/TableValues.tsx';
export default function CreateForm(){
const DisplayData=JsonData.map(
(info)=>{
return(
<tr>
<td>{info.first_name}</td>
<td>{info.last_name}</td>
<td>{info.Category}</td>
</tr>
)
}
)
const DisplayRegisterData = () => {
return(
<div>
<table>
<thead>
<tr>
<th>{RegistrationTableHeader.first_name}</th>
<th>{RegistrationTableHeader.last_name}</th>
<th>{RegistrationTableHeader.Category}</th>
</tr>
</thead>
<tbody>
{DisplayData}
</tbody>
</table>
</div>
)
}
return(
<div className='containerBox'>
<CustomTextbox
label='First Name'
placeholder='First Name' />
<CustomTextbox
label='Last Name'
placeholder='Last Name' />
<CustomPersonDropDownButton />
<CustomButton
title='Register person' onClick={DisplayRegisterData}/>
</div>
)
}
I tried to create a separate file/component with the code for table, and call it on a onClick event but is not working. If I separate the component and I put it off the onClick event, the component is rendering with data but I want to render here only when I click the button.
You are supposed to place your table data directly as part of your template, but hiding / showing it based on a state flag, see React doc about conditional rendering:
function Form() {
const [showTable, setShowTable] = React.useState(false);
return (
<>
<button onClick={() => setShowTable(true)}>Show Table</button>
{
// Conditionally render the table
showTable && <table></table>
}
</>
);
}
You can also separate some parts as "sub-templates", in which case you would call them as a normal function ({DisplayRegisterData()}), but make sure not to turn them into Components (do not use hooks inside sub-templates):
function Form() {
const [showTable, setShowTable] = React.useState(false);
// Sub-template
const DisplayRegisterData = () => {
// Do NOT use hooks here!
return <table></table>;
}
return (
<>
<button onClick={() => setShowTable(true)}>Show Table</button>
{
// Conditionally render the table
showTable && DisplayRegisterData()
}
</>
);
}

why onClick isn't working on my react project

onclick isn't working on my react component, here is my code:
const listItems = xox.map((nums) =>
<Square key={nums.index} cont={nums.content} onclick={function (){
alert();
}}/>
);
also i tried this but alert working on the when render the page:
<Square key={nums.index} cont={nums.content} onclick={alert()}/>
my app function:
function App() {
return (
<div className="App">
<header>
<img src={logo} alt="React logo"/>
<h1>XOX</h1>
</header>
<div className="playground">
{listItems}
</div>
</div>
);
}
Square.js
import React from "react";
export class Square extends React.Component {
render() {
return (
<div className="square" onClick={this.props.onclick}>
{this.props.cont}
</div>
)
}
}
You need to make sure your Square component accepts and then uses an onclick prop. For example, something like:
const Square = ({ cont, onclick }) => (
<div onClick={onclick}>{cont}</div>
);
Otherwise the prop will be ignored, since it's not used inside the component.
also i tried this but alert working on the when render the page:
Yes, you need to pass a function as a prop, not invoke the function then pass the result as a prop. This:
return <Square key={nums.index} cont={nums.content} onclick={alert()}/>
is equivalent to doing
const result = alert();
return <Square key={nums.index} cont={nums.content} onclick={result}/>;
So you instead need
onclick={() => alert()}
(or with the function keyword as you're already doing, though it's less terse)
If possible, I'd also suggest using the standard capitalization for React click handlers, which is onClick, not onclick - there's less chance of confusing people that way.
try using arrow functions:
<Square key={nums.index} cont={nums.content} onClick={() => alert('hello world')}/>

How to conditional render inside map in a functional component of react js

I have an array. in which i want to iterate over and do conditional checks and display the correct element. i'm using functional component.
Below is an example :
import React, { useState, useEffect } from "react";
function Job(props) {
const [resp_data, setdata] = useState("");
const [look, setlook] = useState("");
useEffect(() => {
// some api calls happen here and response data is stored in state resp_data
}, [props]);
return (
<>
<div className="product_list">
{resp_data.length > 0
? resp_data.map((item) => {
{item.looking_for === "work" ? (
<div className="card-rows work" key={item.id}>
work
</div>
) : (<div className="card-rows no_work" key={item.id}>
No work
</div>)
}
})
: <div>array length is 0</div>}
</div>
</>
);
}
export default Job;
The response data received from api call happening inside useEffect is stored in state variable resp_data.
if resp_data length is not zero, i need to iterate over the list and check if the field value "looking_for" is equal to "work"
if true display a component , else display another component.
if resp_data length is zero display "array length is zero"
this i want to implement, but i could not find many answers for functional components. i have tried many possible ways by switching, changing the braces etc..my hard luck.
Any help is greatly appreciated.
You are not returning anything from the 'map' function.
resp_data.map((item) => (
item.looking_for === "work" ? (
<div className="card-rows work" key={item.id}>
work
</div>
) : (<div className="card-rows no_work" key={item.id}>
No work
</div>)
)
)

React: Child Components Failed to Receive Multiple Mapped Data Using Props

I'm new to react. I want to create a simple react web app that receives data from 2 api, and display the data.
I have three components. App.js receive data from two api, and pass the data to FruitGrid.js using hooks and props. FruitGrid.js map the two data received, and pass to FruitItem.
My problem is in FruitGrid.js. Data is received in FruitGrid.js, I can see by console log or print using html tags. But when I try to send the mapped data to FruitItem.js by changing the h1 tag to <FruitItem></FruitItem>, I can only successfully pass one data, not both of them.
FruitGrid.js
import React from 'react';
import FruitItem from './FruitItem';
const FruitGrid = ({ items, images, isLoading }) => {
return isLoading ? (
<h1>Loading...</h1>
) : (
<section>
{items.map((item) => {
return <FruitItem key={item.id} item={item}></FruitItem>
})}
{images.map(image => {
return <FruitItem key={image.id} image={image}></FruitItem>
// return <h1>{image}</h1>
})}
</section>
)
}
export default FruitGrid;
If I only do return <FruitItem key={item.id} item={item}></FruitItem> the item data will show in the correct layout, image won't show since I didn't pass. But if I try to pass both item and image using <FruitItem></FruitItem>. It will show error saying "TypeError: Cannot read property 'name' of undefined" in FruitItem.
FruitItem.js
import React from 'react'
const FruitItem = ({ item, image }) => {
return (
<div className='card'>
<div className='card-inner'>
<div className='card-front'>
<img src={image} alt='' />
</div>
<div className='card-back'>
<h1>{item.name}</h1>
<ul>
</ul>
</div>
</div>
</div>
)
}
export default FruitItem
Can someone help and let me know how i can fix it?
Hey #yywhocodes this is happening because the FruitItem.js is always expecting an item object and your code for the images mapping is not providing the item object -> return <FruitItem key={image.id} image={image}></FruitItem>
What you can do is change the FruitItem.js
from
<h1>{item.name}</h1>
to
{ item ? <h1>{item.name}</h1> : null }
like that it will try to render the item.name only if the item exists.
You are iterating over the two data sources separately, so items are not defined in your images.map and images are not defined in your items.map
In order to combine, assuming the order of the data is the same/the keys are the same in both cases, you could do something like this:
{items.map((item, key) => {
return <FruitItem key={item.id} item={item} image={images[key]}></FruitItem>
})}
You need to pass props key={item.id} item={item} to the child FruitItem component. If you can't pass any props to the FruitItem component, react won't figure out the item.name. Which will be a TypeError.
It's because your FruitItem always expects an item to be handed in
<h1>{item.name}</h1>
But when you hand in your image, there is no item you set.

How to measure a rows height in react-virtualized list

I'm a little uncertain as how to achieve dynamic heights of a List using react-virtualized.
I have a component as follows:
import { List } from 'react-virtualized';
<List
height={400}
rowCount={_.size(messages)}
rowHeight={(index) => {
return 100; // This needs to measure the dom.
}}
rowRenderer={({ key, index, style }) => <Message style={style} {...messages[index]} />}}
width={300}
/>
I have looked at using CellMeasurer as per the docs which says it can be used with the List component but I have no idea how this example actually works...
I've also tried to work out how it has been achieved in the demo code but have also reached a dead end.
Can someone please assist me on how I would measure the DOM to get each items height dynamically.
Sorry you found the docs to be confusing. I will try to update them to be clearer. Hopefully this will help:
import { CellMeasurer, List } from 'react-virtualized';
function renderList (listProps) {
return (
<CellMeasurer
cellRenderer={
// CellMeasurer expects to work with a Grid
// But your rowRenderer was written for a List
// The only difference is the named parameter they
// So map the Grid params (eg rowIndex) to List params (eg index)
({ rowIndex, ...rest }) => listProps.cellRenderer({ index: rowIndex, ...rest })
}
columnCount={1}
rowCount={listProps.rowCount}
width={listProps.width}
>
{({ getRowHeight, setRef }) => (
<List
{...listProps}
ref={setRef}
rowHeight={getRowHeight}
/>
)}
</CellMeasurer>
)
}
There are also demos of this component here showing how it's used.

Categories