Component output by pressing the ReactJS button using the props - reactjs

I have 2 buttons, when I click on one of them, the component will be displayed in tr className = "info". The code is made so that it is universal, if there are 50 different components, then there will be 50 different buttons. And the active button will change the class. I'm trying to do it now with the help of a props, I'm just learning, tell me, please, where is the mistake?
import React, { Component } from 'react';
import './App.css';
import Donald from '/.Donald';
import John from '/.John';
const Counter =({buttonType,id})=>{
const {
buttonType,
children,
} = props;
return (
<div
className = {`${buttonType}`}
onClick={id}
>
{children}
</div>
);
}
Counter.defaultProps={
className = 'notActive'
}
class MyName extends Component {
state = {
array:[
{id:1,component:<Donald/>, name:"My name Donald"},
{id:2,component:<John/>, name:"My name John"},
],
};
render() {
const selectedElement = this.state.array.find(item => item.id === this.state.currComponentId);
return(
<table>
<tbody>
<tr className="trButton">
{
this.state.array.map( (element) => {
return (
<Counter>
<td
className={'active'}
onClick={ () => this.element.id}
>{element.name}
</td>
</Counter>
)
})
}
</tr>
<tr className="info">
{selectedElement.component}
</tr>
</tbody>
</table>
)
}
}
export default MyName;

I see couple of issues with the code
(1) Firstly, I think you are using incorrect path for import these components i.e. Use ./Donald instead of /.Donald (notice the . before / not after), similarly './John'.
(2) Secondly you're not setting initial value for currComponentId in state. Lets set that too
state = {
array:[
{id: 1, component: <Donald/>, name:"My name Donald"},
{id: 2, component: <John/>, name:"My name John"},
],
currComponentId: 1
};
(3) Also I think you are trying to change the currComponentId in onClick. So it will be
<Counter>
<td
className={'active'}
onClick={ () => this.setState({currComponentId: element.id})}
>
{element.name}
</td>
</Counter>

Related

How can I ensure that only the parent element is captured for a click event?

I have this simple Ticket React component. I want to only capture the surrounding <tr> parent element, but sometimes if I click on one of the table cells it will give me a <td> element.
import React from "react";
import styles from "./Ticket.module.css";
const Ticket = (props) => {
let toggleModal = props.onToggleModal;
const eventToggle = (event) => {
// console.log(event.target.innerText);
toggleModal(event);
}
return (
<tr className={styles.ticket} onClick={eventToggle}>
<td className={styles["ticket-col"]}>
<div>
{props.ticket.task}
</div>
</td>
<td className={styles["ticket-col"]}>
<div>
{props.ticket.assignee}
</div>
</td>
<td className={styles["ticket-col"]}>
<div>
{props.ticket.time}
</div>
</td>
</tr>
);
};
export default Ticket;
Check that the event.target (the innermost item that was clicked on) is a <tr>, and not anything else. (Otherwise, if it's a <td> or a <div> or something else, the click was on some other inner element.)
const Ticket = (props) => {
const eventToggle = (event) => {
if (event.target.matches('tr')) {
props.onToggleModal(event);
}
};

Cannot update a component (`App`) while rendering a different component (`UserTable`)

I'm trying to learn React Hooks in functional components, and am following along with React Hooks tutorial but am getting the error: Cannot update a component (App) while rendering a different component (UserTable), and the error stack indicates this is related to the onClick={props.deleteUser(user.id)} property in the delete button in UserTable.js. I saw several posts indicating that one should try useEffect() to get around this issue, so I tried having deleteUser update a state variable, and then have useEffects change the users array. While the code compiled fine, the page simply hung and eventually timed out with an "out of memory" error (I assume caused by an endless cycle of trying to render and re-render?). Any ideas how to fix this situation?
App.js
import React, { useState } from 'react';
import UserTable from './tables/UserTable';
import AddUserForm from './forms/AddUserForm';
const App= () => {
const usersData = [
{id: 1, name: "Tania", username: "floppydiskette"},
{id: 2, name: "Craig", username: "siliconeidolon" },
{id: 3, name: "Ben", username: "benisphere"}
]
const [users, setUsers] = useState(usersData);
const addUser = (user) => {
user.id = users.length+1;
setUsers([...users,user])
}
const deleteUser = (id) => {
setUsers(users.filter((user)=>user.id !== id))
}
return (
<div className="container">
<h1> SIMPLE CRUD APP WITH HOOKS</h1>
<div className="flex-row">
<div className = "flex-large">
<h2> Add User </h2>
<AddUserForm addUser={addUser}/>
</div>
<div className = "flex-large">
<h2>View Users</h2>
<UserTable users={users} deleteUser={deleteUser}/>
</div>
</div>
</div>
);
}
export default App;
UserTable.js
import React from 'react';
const UserTable = (props) => {
return(
<table>
<thead>
<tr>
<th>Name</th>
<th>UserName</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{props.users.length > 0 ? (
props.users.map((user) => (
<tr key={user.id}>
<td>{user.name}</td>
<td>{user.username}</td>
<td>
<button className="button muted-button">Edit</button>
>>> This triggers the `cannot update a component . . .` error:
<button className="button muted-button" onClick={props.deleteUser(user.id)}>Delete</button>
</td>
</tr>
))
) : (
<tr colspan={3}>No Users</tr>
)}
</tbody>
</table>
);
}
export default UserTable
You just have to change
onClick={props.deleteUser(user.id)}>Delete</button>
to
onClick={()=> props.deleteUser(user.id)}>Delete</button>
Otherwise your delete function will get automaticaly fired on render itself

React JS assign separate onclick event to every row of table

I have a table which have a setting icon as the last column and whenever a user clicks on it, it should pop open a setting menu. To toggle between active class I used state and passed it to the array.map function, but what is happening is whenever a user clicks on one setting icon all the menus open simultaneously and the reason is they all have same click event and same state variable. How can I change it to where only the clicked setting icon should have its menu opened? My code is given below.
import React, { Component, PropTypes } from 'react';
import '../../../assets/custom_css/tables/unstackable_very_basic_striped_users_table.css';
import { v4 } from 'node-uuid';
import Language from '../../../assets/language';
class UnstackableVeryBasicStripedUsersTable extends Component {
static propTypes = {
rows: PropTypes.array.isRequired
};
constructor(props) {
super(props);
this.getTableRows = this.getTableRows.bind(this);
this.open_setting_menu = this.open_setting_menu.bind(this);
this.state = {
is_action_menu_active: false
};
}
getTableRows() {
const { rows } = this.props;
return rows.map(row => {
let drop_down_class = (this.state.is_action_menu_active) ? "active" : "";
let menu_class = (this.state.is_action_menu_active) ? "transition visible" : "";
return <tr key={v4()}>
{row.map(info => {
return <td key={v4()}>
{info}
</td>
})}
<td>
<div className={"ui right pointing dropdown icon " + drop_down_class} onClick={this.open_setting_menu}>
<i className="setting icon"/>
<div className={"menu " + menu_class}>
<div className="item">Edit</div>
<div className="item">Delete</div>
</div>
</div>
</td>
</tr>
});
}
open_setting_menu() {
this.setState({
is_action_menu_active: !this.state.is_action_menu_active
});
}
render() {
return <table className="ui unstackable celled very basic striped table unstackable_very_basic_striped_table">
<thead>
<tr>
<th>{Language.name}</th>
<th>{Language.role}</th>
<th>{Language.department}</th>
<th>{Language.action}</th>
</tr>
</thead>
<tbody>
{this.getTableRows()}
</tbody>
</table>
}
}
export default UnstackableVeryBasicStripedUsersTable;
If you want to use a single component, you can save the index of the selected row in the state:
import React, { Component, PropTypes } from 'react';
import '../../../assets/custom_css/tables/unstackable_very_basic_striped_users_table.css';
import { v4 } from 'node-uuid';
import Language from '../../../assets/language';
class UnstackableVeryBasicStripedUsersTable extends Component {
static propTypes = {
rows: PropTypes.array.isRequired
};
constructor(props) {
super(props);
this.getTableRows = this.getTableRows.bind(this);
this.open_setting_menu = this.open_setting_menu.bind(this);
this.state = {
selected_row_index: 0,
is_action_menu_active: false
};
}
getTableRows() {
const { rows } = this.props;
return rows.map((row, index) => {
let drop_down_class = (this.state.is_action_menu_active && this.state.selected_row_index === index) ? "active" : "";
let menu_class = (this.state.is_action_menu_active && this.state.selected_row_index === index) ? "transition visible" : "";
return <tr key={v4()}>
{row.map(info => {
return <td key={v4()}>
{info}
</td>
})}
<td>
<div className={"ui right pointing dropdown icon " + drop_down_class} onClick={() => this.open_setting_menu(index)}>
<i className="setting icon"/>
<div className={"menu " + menu_class}>
<div className="item">Edit</div>
<div className="item">Delete</div>
</div>
</div>
</td>
</tr>
});
}
open_setting_menu(index) {
this.setState({
is_action_menu_active: !this.state.is_action_menu_active,
selected_row_index: index
});
}
render() {
return <table className="ui unstackable celled very basic striped table unstackable_very_basic_striped_table">
<thead>
<tr>
<th>{Language.name}</th>
<th>{Language.role}</th>
<th>{Language.department}</th>
<th>{Language.action}</th>
</tr>
</thead>
<tbody>
{this.getTableRows()}
</tbody>
</table>
}
}
export default UnstackableVeryBasicStripedUsersTable;

React - why is this component not rendering anything?

I am trying to render some child components in a parent component but nothing is rendering. I'm not getting any console errors but there is no render. I can't figure out why this may be happening. The application I am working on is built with React, using a flux architecture.
Here is my code:
Parent Component:
import React from 'react';
import TableWithDataHeader from './TableWithDataHeader.jsx';
import TableWithDataBody from './TableWithDataBody.jsx';
import TableWithDataRowForm from './TableWithDataRowForm.jsx';
import AppStore from '../../stores/AppStore';
export default class TableWithData extends React.Component {
state = {rows: [], isEditing: false};
componentDidMount() {
let json = AppStore.getCells();
let rows = this.state.rows;
for (let key in json) {
{rows[key] = json[key]};
}
this.setState({rows});
console.log(rows);
}
handleEdit = (row) => {
this.setState({isEditing: true});
};
editStop = (formKey) => {
this.setState({isEditing: false});
};
handleSubmit = () => {
console.log('hello');
};
render() {
let {rows, isEditing} = this.state;
console.log(rows);
return (
<div>
<div className="row">
<table className="table table-striped">
<thead>
<TableWithDataHeader />
</thead>
<tbody>
{rows.map(row => this.state.isEditing ?
<TableWithDataRowForm formKey={row.id} key={row.id} editStop={this.editStop(formKey)} handleSubmit={this.handleSubmit} /> :
<TableWithDataBody key={row.id} value={row.historycells.contents} handleEdit={this.handleEdit(row)} />
)}
</tbody>
</table>
</div>
</div>
);
}
}
RowForm:
import React from 'react';
export default class TableWithDataRowForm extends React.Component {
editStop = () => {
this.props.editStop();
};
handleSubmit = (e) => {
e.preventDefault();
this.props.handleSubmit();
};
render() {
return (
<tr>
<td></td>
<td>
<button className=""><i className="btn btn-default" onClick={this.editStop}></i>Cancel</button>
<button className="btn btn-success"><i className="fa fa-cloud" onClick={this.handleSubmit}></i>Save</button>
</td>
</tr>
);
}
}
Table Head:
import React from 'react';
import AppStore from '../../stores/AppStore';
export default class TableWithDataHeader extends React.Component {
addHeaders() {
let headerArray = AppStore.getTable().columns;
let headerList = headerArray.map((element, index) => {
return (
<th key={index} id={element.id} className="text-center">{element.name}</th>
);
});
return headerList;
}
render() {
return (
<tr>
{this.addHeaders()}
<th></th>
</tr>
);
}
}
Table Body:
import React from 'react';
export default class TableWithDataBody extends React.Component {
handleEdit() {
this.props.handleEdit();
}
render() {
return (
<tr>
{this.props.histroycells.map(cell => {
return <Cell key={cell.id} value={cell.contents} />
})}
<td>
<button className="btn btn-primary" onClick={this.handleEdit}><i className="fa fa-pencil"></i>Edit</button>
</td>
</tr>
);
}
}
The table header renders fine but neither the body of the table or the edit form shows up at all!
Any help would be much appreciated, especially examples!
Thanks for you time!
Maybe this will help:
Inside your <TableWithDataBody>component, you try to access this.props.historycells, but this isn't passed as a prop.
You render your table rows with:
<TableWithDataBody
key={row.id}
value={row.historycells.contents}
handleEdit={this.handleEdit(row)} />
Maybe if you change render to:
<TableWithDataBody
key={row.id}
historycells={row.historycells} // changed this parameter
handleEdit={this.handleEdit(row)} />
UPDATE:
The line which loops over the props should still read:
{this.props.historycells.map(cell => {
PS: please also fix typo in histroycells.
You have a typo in your code. histroycells in TableWithDataBody should be historycells.

React - appending an empty row to a table

I am currently building an application that renders a table but in the first instance the only thing that renders are the column headers. What I would like to know is how I would then go about giving a user the choice to add a row with no data that they can then edit to add data that they want to put in the cells of the row. The headers are generated by a form with a dynamic amount of inputs so theoretically there could be a lot and the added row would need to reflect this also. I would like to try and avoid using a plugin if possible as well.
The app is being built with React and for the moment I am using flux architecture.
Fast answers with examples would be very much appreciated!
Thanks for your time
Here is where the whole table renders:
import React from 'react';
import TableHeader from './TableHeader.jsx';
import TableBody from './TableBody.jsx';
export default class Table extends React.Component {
render() {
return (
<table className="table table-striped dali-table">
<thead><TableHeader /></thead>
<tbody><TableBody /></tbody>
</table>
);
}
}
Here is the code for rendering the column headers:
import React from 'react';
import AppStore from '../../stores/AppStore';
export default class TableHeader extends React.Component {
addHeaders() {
let headerArray = AppStore.getTable().columns;
let headerList = headerArray.map((element, index) => {
return (
<th key={index} id={element.id} className="text-center">{element.name}</th>
);
});
return headerList;
}
render() {
return (
<tr>{this.addHeaders()}</tr>
);
}
}
And I don't really have any code for the body of the table, as that is the bit which I am struggling with!
Okay so I think I'm making some headway! Thanks for the help so far! Here is what I have at the moment (I will be separating it out later, just want to get it working first!):
import React from 'react';
import AppStore from '../../stores/AppStore';
export default class Table extends React.Component {
state = {rows: [], isEditing: false};
render() {
let {rows, isEditing} = this.state;
let headerArray = AppStore.getTable().columns;
const handleEdit = (row) => {
this.setState({isEditing: true});
};
const handleAddRowClickEvent = () => {
let rows = this.state.rows;
rows.push({isNew: true, isEditing: false});
this.setState({rows: rows});
};
return (
<div>
<div className="row" id="table-row">
<table className="table table-striped">
<thead>
<tr>{headerArray.map((element, index) => {
return (
<th key={index} id={element.id} className="text-center">{element.name}</th>
);})}
</tr>
</thead>
<tbody>
{rows.map((row, index) => row.isEditing ?
<RowForm formKey={index} key={index} /> :
<tr key={index}>
{headerArray.map((element, index) => {
return (
<td key={index} id={element.id}></td>
);
})}
<td>
<button onClick={handleEdit(row)}>Edit</button>
</td>
</tr>)}
</tbody>
</table>
</div>
<div className="row">
<div className="col-xs-12 de-button">
<button type="button" className="btn btn-success" onClick={handleAddRowClickEvent}>Add Row</button>
</div>
</div>
</div>
);
}
}
Need help on adding the row don't know what to push into the empty rows array! Thanks
The main idea is add flag to each row so you can know the status for each row, is it in edit mode or display mode
render(){
const handleEdit = (row) => {
// toggle isEditing flag
};
return (<tbody>
{
rows.map((row) => row.isEditing ?
<RowForm formKey={row.id} key={row.id}/> :
<tr key={row.id}>
<td>{row.id}</td>
<td>{row.name}</td>
<button onClick={handleEdit(row)}>
Edit
</button>
</td>
</tr>
}
</tbody>);
}
Check this example source code / demo
Posting some code snippets will help one provide better answers
So, to create a dynamic row you could do something like:
import React from 'react';
import AppStore from '../../stores/AppStore';
export default class TableBody extends React.Component {
addRows() {
// This gets the number of columns in your header from your backend
let noOfColumns = AppStore.getColumnSize();
// loop from 1 to noOfColumns and return:
return (
<td><input placeholder='Enter Value'/></td>
);
}
render() {
return (
<tr>{this.addRows()}</tr>
);
}
}
Then add TableBody to your Table Class.
PS - The above is just code snippets and is somewhat pseudo-code. You also need to handle the 'input field' correctly as per React Documentation recommendation: https://facebook.github.io/react/docs/forms.html

Resources