Render class conditionally in React - javascript

I'm trying to render a class conditionally. If the mapped item is blank, I'd like there to be a class that renders. Otherwise, no changes. I'm sure this very simple but I'm new at this and not sure how to identify the blank item. Is this a problem with scope? This is the code in my component:
const TableBody = (props) => {
let classes = ''
classes += (props.data.map === '') ? '' : 'collapse'
return (
<tbody>
{props.data.map((item, index) => (
<tr key={typy(item, 'sys.id').safeString || index}>
{props.columns.map(column =>
<td className={classes} role='cell' key={column.label}>{typy(item, column.path).safeObject}</td>)
}
</tr>
))}
</tbody>
)
}
All of the <td> elements are collapsed so the code I'm using above must not be properly detecting a blank value. Can anyone point me in the right direction here?

Per my comment, props.data appears to be an array. You are checking to see if props.data.map === '', which will always evaluate to false. You should probably fix that statement, otherwise the class will always be 'collapse'. Hope that helps!

Related

React: How to deal with large td Input element in Table that re-render everytime when state changed occurs?

I'm not sure if this is the right way to push table element in React, but I've been doing this all the time. So this for loop below will get executed everytime re-render occurs or in this case when I change my input. what if I have like 100 Input?
Questions:
Is this the right way to draw table element?
wouldn't re-render cause bad performance especially if you have some kind of loop before return?
If this is not the right way to do it. Please show me the right way to do it.
function App() {
const [inputs,setInputs] = useState({input1:'',input2:'',input3:''})
function handleOnChange(e){
const {name,value} = e.target
setInputs(prev => ({...prev, [name]:value}))
}
let tableElement = []
for(let i = 1; i <= 3; i++){
tableElement.push(<tr key={i}>
<td><Input value={inputs[`${i}`]} name={`input${i}`} onChange={handleOnChange} /></td>
</tr>)
}
return (
<div>
<Table>
<tbody>
{tableElement}
</tbody>
</Table>
</div>
);
}
export default App;
Given code:
let tableElement = []
for (let i = 1; i <= 3; i++){
tableElement.push((
<tr key={i}>
<td>
<Input value={inputs[`${i}`]} name={`input${i}`} onChange={handleOnChange} />
</td>
</tr>
))
}
return (
<div>
<Table>
<tbody>
{tableElement}
</tbody>
</Table>
</div>
);
Questions:
Is this the right way to draw table element?
It isn't wrong, though it may not be the most common way to render out an array to JSX. Typically you may opt to map an array to JSX
const tableElement = [...Array(3).keys()].map((i) => (
<tr key={i}>
<td>
<Input value={inputs[`${i}`]} name={`input${i}`} onChange={handleOnChange} />
</td>
</tr>
));
return (
<div>
<Table>
<tbody>
{tableElement}
</tbody>
</Table>
</div>
);
Or directly in the JSX
return (
<div>
<Table>
<tbody>
{[...Array(3).keys()].map((i) => (
<tr key={i}>
<td>
<Input
value={inputs[`${i}`]}
name={`input${i}`}
onChange={handleOnChange}
/>
</td>
</tr>
))}
</tbody>
</Table>
</div>
);
wouldn't re-render cause bad performance especially if you have some kind of loop before return?
I suppose there is a potential for poor performance, but due to the nature of the UI needing to map out a bunch of array elements when the component renders this is work that would be necessary anyway.
React is already pretty optimized out-of-the-box. It uses a reconciliation process to determine what mapped elements actually changed from the previous render and only rerenders what is necessary. The React key is used when mapping arrays to help in this regard.
If this is not the right way to do it. Please show me the right way to do it.
I shared the more common methods of mapping an array to JSX in point #1 above.

React/preact OnClick <td> render table with details

I have a Table which when you click a td tag that is an plusbutton it should show the details about that row. Something like this:
Right now I am just testing it like this:
props.info.map((l, i) => {
return (
<tr>
<td>{i + 1}</td>
<td>{l.UserId}</td>
<td onClick={props.onShowInfoDetails}>
<MenuPlusButton /></td>
{props.showInfoDetails && (
<DetailsTable />
)
}
</tr>
)
})
where the DetailsTable is the thing i want to render onClick
export const DetailsTable = (props: Props) => {
return (
<tr>
<td>Hello</td>
</tr>
)
}
There is two problems with this. First the DetailsTable renders to the right of the rest of the content and not under it like in the picture. second problem is that when I click it all table rows show the hello not just the one that I clicked. Both of these I can't seem to figure out. The second problem I guess is because it says if props.showEntryDetails is true it renders the DetailsTable and the onClick sets it to true but how do I make it so it's only true for that row that I clicked?

Dynamically Creating Table Rows With React

I am trying to create a Table using React and React-Bootstrap that has a custom number of table rows. The table is supposed to store data about player statistics of a certain video game, and based on the video game the statistics may change, thus the number of rows and titles of these rows must be able to dynamically change as well. I wanted to create an array in the state that held the list of current statistics, then map this array to a element using the map function and render the table. However, after trying several approaches I can't get any of the custom input to render. Below is the code :
Class Structure
class Statistics extends Component {
constructor(props) {
super(props)
this.state = {
game: '',
player_names: [],
positions: [],
stat_categories: [
'kills',
'deaths',
'assists'
]
}
}
renderTableRows(array) {
return (
<tr>
<th> NAME </th>
<th> TEAM </th>
<th> POSITION </th>
{ array.map(item => {
console.log(item)
<th key={item}> {item} </th>
})
}
</tr>
)
}
render() {
const columnLength = this.state.player_names.length
const statCols = this.state.stat_categories
return (
<div>
<MyNav url={this.props.location.pathname} />
<Table responsive striped bordered hover>
<thead>
{ this.renderTableRows(statCols) }
</thead>
</Table>
</div>
)
}
}
The console also properly logs the data in state (kills, deaths, assists) -- so the issue is when rendering the element. Any help would be appreciated!
You have no return statement in your map function, inside of renderTableRows.
When using ES6 arrow functions, you can either:
Return data directly without a return statement
(args) => (returnedData);
Or add some logic instead of just returning directly,
(args) => {
// Logic here
return returnedData
}
In the second case you'll need a return statement, because you are logging, if you choose to remove logging, go the first way.
Also, please post the code directly in your question, as using an image makes it less readable and not indexed by search engines.
You have to render each item in separate trs, not as a series of ths
renderTableCols(array) {
return array.map(item => <th>{item}</th>)
}
renderTableColValues(item, cols) {
return cols.map(col => <td>{item[col]}</td>)
}
renderTableRows(array) {
return array.map(item =>
<tr>
<td>{item.name}</td>
<td>{item.team}</td>
<td>{item.position}</td>
{this.renderTableColValues(item, this.cols)}
</tr>
);
}
render() {
return (
<Table>
<thead>
<tr>
<th>NAME</th>
<th>TEAM</th>
<th>POSITION</th>
{this.renderTableCols(this.cols)}
</tr>
</thead>
<tbody>
{this.renderTableRows(items)}
</tbody>
</Table>
);
}
More on tables https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table
I will give you a similar answer of what youre encoutering but its kinda different approach with a excelent solution
So, you are trying to create a dynamic table but youre making table rows static, what i did was letting the table to receive arrays of head and data and then create as many rows or datas that are required.
heres the code
export function objectIntoTableData(object) {
return Object.values(object).map((data, index) => {
return <td key={index}>{data}</td>;
});
}
You must change this index to (value,index) => , thats just my use
tableRows(data) {
return data.map(value => {
return <tr key={value.index}>{objectIntoTableData(value)}</tr>;
});
}
<thead>
<tr>
{head.map((value, index) => {
return <th key={index}>{value}</th>;
})}
</tr>
</thead>
<tbody>{this.tableRows(data)}</tbody>
Rather use a id or index inside your object since the index callback of the map function, its unsafe to use for the keys.
<ReactTableUse
head={["#", "Cell1", "Cell2", "Cell3"]}
data={[{id:1, test:1},{id:2, test:2}]}
/>
Rules:
When your state changes, render method of a class based component will be called.
Question: Who will change the state? will it grow inside the component ? What is your problem ? your are not being able to render anything ? or statistics is not dynamically rendering ? if you want to change it dynamically , you need to change the state first.

react.js how to get prop form tree element

I am trying to make table cell editable after clicking on icon in another cell , for that I need to get index of element so the editor will open in the correct row , which icon belongs to.
My issue is that I dont know the way i should get the prop value of table DOM element here is code for for clearify
a part of dom tree generated with react:
<tbody>
{stepsDone.map(function(step,idx) {
let content = step;
const editing = this.state.editing;
if(editing){
content = (
<form onSubmit={this._save}>
<input type="text" defaultValue={step} />
</form>
);
}
return(
<tr key={idx}>
<td className="step" data-step={'step'+idx}>{content}</td>
<td className="icRow">
<Icon className="edit" onClick={this._showEditor} rownum={idx}/>
<Icon className="remove"/>
<Icon className="trash outline"/>
</td>
</tr>
)
},this)}
show editor function:
_showEditor(e){
this.setState({
editing:{
row:e.target.rownum
}
});
console.log(this.state.editing);
}
After execution of showedtior function console logs :
first click = null , which is normal i think
more clicks = undefined , and thats whats brings a trouble i want to receive idx from map function.
here is code from Icon.js
import React from 'react';
import classNames from 'classnames';
export function Icon(props) {
const cssclasses = classNames('icon', props.className);
return <i className={cssclasses} onClick={props.onClick}/>;
}
if you want to reveive the idx from the map function you should pass it to the function _showEditor so your code must be like this :
<Icon className="edit" onClick={this._showEditor(idx)}/>
and the function definition should be :
_showEditor = (idx) => (event) => {
this.setState({
editing:{
row:idx
}
});
console.log(this.state.editing);
}
or if you don't want to use the arrow functions for some reason, just replace
onClick={this._showEditor(idx)}
with
onClick={this._showEditor.bind(this,idx)}
and its definition becomes
_showEditor(idx){...}

Rendering "a" with optional href in React.js

I need to render a table with a link in one of the columns, and searching for a most elegant way to do it. My main problem is - not all table rows are supplied with that link. If link is present - I need that "a" tag rendered. If not - no need for "a" tag at all. Generally speaking I would like react to handle that choice (render vs not render) depending on this.state.
This is what I have at the moment.
React.createClass({
getInitialState: function () {
return {
pipeline: this.props.data.pipeline,
liveUrl: this.props.data.liveUrl,
posted: this.props.data.created,
expires: this.props.data.end
};
},
render: function () {
return (
<tr className="posting-list">
<td>{this.state.pipeline}</td>
<td>Posted</td>
<td>
<input className="datepicker" type="text" value={this.state.posted}/>
</td>
<td>
<input className="datepicker" type="text" value={this.state.expires}/>
</td>
<td>UPDATE, DELETE</td>
</tr>
);
}
});
This results is DOM element :
XING_batch
This is not acceptable solution for me, because those blank hrefs are still clickable.
I also tried adding some logic to getInitalState(
liveUrl: (this.props.data.liveUrl !== "") ? this.props.data.liveUrl : "javascript:void;",
), which worked fine, but looks weird, and adds errors in console(Uncaught SyntaxError: Unexpected token ;)
The only way I've got left is creating 2 different components for
It's just JavaScript, so you can use any logic you like, e.g.:
<td>
{this.state.liveUrl
? <a ...>{this.state.pipeline}</a>
: this.state.pipeline}
</td>
You can choose the type of component at runtime, as well:
import * as React from "react";
const FooBar = props => {
const Component = props.href ? "a" : "div";
return (
<Component href={href}>
{props.children}
</Component>
);
};
<FooBar>Hello</FooBar> // <div>Hello</div>
<FooBar href="/">World</FooBar> // World
Take a look at spread properties:
You could use them like this for example:
var extras = { };
if (this.state.liveUrl) { extras.href = this.state.liveUrl; }
return <a {...extras} >My link</a>;
The values are merged with directly set properties. If they're not on the object, they're excluded.

Categories

Resources