React 'this' Context within Method - reactjs

I am trying to call a Method on a Button click like this (the button is returned within a method itself):
<button onClick={removeClick}>Remove</button>
this is the method i am trying to call
removeClick = event => {
console.log('clicked');
};
im always getting errors like '_this2 is undefined'
i have already tried binding the method in the constructor.
an arrow function within the onClick didn't work as well
removeClick = event => {
console.log('clicked');
};
renderWeather(cityData) {
const name = cityData.city.name;
const temps = cityData.list.map(weather => weather.main.temp - 273.15);
const pressures = cityData.list.map(weather => weather.main.pressure);
const humidities = cityData.list.map(weather => weather.main.humidity);
const { lon, lat } = cityData.city.coord;
return (
<tr key={lon + lat}>
<td>
<GoogleMap lon={lon} lat={lat} />
<span className="city-name">{name}</span>
</td>
<td>
<WeatherChart data={temps} color="red" unit="°C" />
</td>
<td>
<WeatherChart data={pressures} color="orange" unit="hPA" />
</td>
<td>
<WeatherChart data={humidities} color="blue" unit="%" />
</td>
<td>
<button onClick={this.removeClick}>Remove</button>
</td>
</tr>
);
}
render() {
return (
<table className="table table-hover">
<thead>
<tr>
<th>City</th>
<th>Temperature (°C) </th>
<th>Pressure (hPA)</th>
<th>Humidity (%)</th>
<th />
</tr>
</thead>
<tbody>{this.props.weather.map(this.renderWeather)}</tbody>
</table>
);
}
}
const mapStateToProps = ({ weather }) => ({
weather
});
const mapDispatchToProps = {
removeCity
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(WeatherList);
this is how the my component looks like
I hope anyone can help me

try
renderWeather = cityData => {
...
}
and because you are using your clickhandler for a set of data you may want to pass some kind of identifier to it
removeClick = id => event => {
console.log(`Removing data for ${id}`)
}
and call it by
<button onClick={() => {this.removeClick(id)}}>Remove</button>

Try to pass this as a second param to map
<tbody>{this.props.weather.map(this.renderWeather, this)}</tbody>
class Item extends React.Component {
removeClick = event => {
console.log('clicked');
}
renderWeather(cityData) {
return <button onClick={this.removeClick}>Remove</button>
}
render() {
return (
<table className="table table-hover">
<thead>
<tr>
<th>City</th>
<th>Temperature (°C) </th>
<th>Pressure (hPA)</th>
<th>Humidity (%)</th>
<th />
</tr>
</thead>
<tbody>{this.props.weather.map(this.renderWeather, this)}</tbody>
</table>
)
}
}
const weather = [
{
city: {name: '123'}
}
];
ReactDOM.render(
<Item weather={weather} />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='root'></div>

Related

react js state value always false

hello im trying to make a array that contain a objects and i want to map this array into two tables :thisis stricture of array:
0
:
{title: 'uml', agreement: false}
1
:
{title: 'react', agreement: false}
2
:
{title: 'laravel', agreement: false}
length
:
3
[[Prototype]]
:
Array(0)
and i have a checkbox that make agreement true or false .
but the problem is everytime the agreement is false.
i want to send objects to first table if is true and to seconde table if is false but everytime is send to first table with false agreement .
this is all of code:
some functions is just to show the values of states
import './App.css';
import { useRef, useState } from 'react';
function App() {
const [modules,setModules]=useState([])
const [agreement,setAgreement]=useState()
const [title,setTitle]=useState()
const checkbox=useRef()
function handlecheck(){
setAgreement(checkbox.current.checked)
}
function handlechange(event){
setTitle(event.target.value)
}
function ajouter(){
setModules([...modules,{title,agreement}])
}
function affich(){
return console.log(modules)
}
return (
<div className="App">
<section class="container cd-table-container">
<h2 class="cd-title">Insert Table Record:</h2>
<input onChange={(event)=>handlechange(event)} type="text" class="cd-search table-filter" data-table="order-table" placeholder="module name" />
<button className='ajouter' onClick={()=>ajouter()} >Ajouter</button>
<button className='ajouter' onClick={()=>affich()} >affich</button>
<input type={"checkbox"} ref={checkbox} onChange={(event)=>handlecheck(event)} />
<table class="cd-table table">
<thead>
<tr>
<th>modules regionaux</th>
</tr>
</thead>
<tbody>
{
modules.map((elm,index)=>{
if(elm.agreement=true){
return (<tr>
<td>{elm.title}</td>
</tr>)
}
})
}
</tbody>
</table>
<br></br>
<table class="cd-table table">
<thead>
<tr>
<th>modules non regionaux</th>
</tr>
</thead>
<tbody>
{
modules.map((elm,index)=>{
if(elm.agreement=false){
return (<tr>
<td>{elm.title}</td>
</tr>)
}
})
}
</tbody>
</table>
</section>
</div>
);
}
export default App;
so first you don't have to use (useRef) hock just use (useState) will be better , second you were using the if statement with the assign operator sign you should use the double equal sign or the triple sign this the full code
import './App.css';
import { useRef, useState } from 'react';
function App() {
const [modules, setModules] = useState([])
const [agreement, setAgreement] = useState()
const [title, setTitle] = useState()
function handlecheck(e) {
setAgreement(e)
}
function handlechange(event) {
setTitle(event.target.value)
}
function ajouter() {
setModules([...modules, { title, agreement }])
}
function affich() {
return console.log(modules)
}
return (
<div className="App">
<section class="container cd-table-container">
<h2 class="cd-title">Insert Table Record:</h2>
<input onChange={(event) => handlechange(event)} type="text" class="cd-search table-filter" data-table="order-table" placeholder="module name" />
<button className='ajouter' onClick={() => ajouter()} >Ajouter</button>
<button className='ajouter' onClick={() => affich()} >affich</button>
<input type={"checkbox"} onChange={(event) => handlecheck(event.target.checked)} />
<table class="cd-table table">
<thead>
<tr>
<th>modules regionaux</th>
</tr>
</thead>
<tbody>
{
modules.map((elm, index) => {
if (elm.agreement === true) {
return (<tr>
<td>{elm.title}</td>
</tr>)
}
})
}
</tbody>
</table>
<br></br>
<table class="cd-table table">
<thead>
<tr>
<th>modules non regionaux</th>
</tr>
</thead>
<tbody>
{
modules.map((elm, index) => {
if (elm.agreement === false) {
return (<tr>
<td>{elm.title}</td>
</tr>)
}
})
}
</tbody>
</table>
</section>
</div>
);
}
export default App;

Display a table in React using different components

I'm just starting to learn React and what I'm trying to do is to display a table. I'm doing it using 3 components: App.js, DisplayTable.js, and TableRows.js. The reason I'm doing it this way is that later on, I will need certain rows of the table to be displayed subject to different conditions. I don't get any error messages, but the table is not being displayed. This is my code:
App.js:
import Form from './components/Form'
import { useState } from 'react'
import TableDisplay from './components/TableDisplay'
const App = () => {
const [rows, setRows] = useState([
{
id:1,
description:'',
semester:'',
prefix:'ENG',
number:'368/371',
grade:'',
editing:''
},
{
id:2,
description:'',
semester:'',
prefix:'',
number:'',
grade:'',
editing:''
},
{
id:3,
description:'',
semester:'',
prefix:'',
number:'',
grade:'',
editing:''
},
])
return (
<div className="container">
<Form/>
<TableDisplay rows={rows}/>
</div>
);
}
export default App;
TableDisplay.js:
import TableRows from "./TableRows"
const TableDisplay = ({rows}) => {
return (
<>
{rows.map((row) => {
<TableRows key={row.id} row={row}/>
})}
</>
)
}
export default TableDisplay
TableRows.js:
import React from 'react'
const TableRows = ({row}) => {
return (
<div className="container">
<table className="table table-striped">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Description</th>
<th scope="col">Semester</th>
<th scope="col">Prefix</th>
<th scope="col">Number</th>
<th scope="col">Grade</th>
<th scope="col">Editing</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">{row.id}</th>
<td>{row.description}</td>
<td>{row.semester}</td>
<td>ENG</td>
<td>368/371</td>
<td>{row.grade}</td>
<td><button type="button" className="btn btn-warning">Edit</button></td>
</tr>
<tr>
<th scope="row">{row.id}</th>
<td>{row.description}</td>
<td>{row.semester}</td>
<td>ENG</td>
<td>368/371</td>
<td>{row.grade}</td>
<td><button type="button" className="btn btn-warning">Edit</button></td>
</tr>
<tr>
<th scope="row">{row.id}</th>
<td>{row.description}</td>
<td>{row.semester}</td>
<td>ENG</td>
<td>368/371</td>
<td>{row.grade}</td>
<td><button type="button" className="btn btn-warning">Edit</button></td>
</tr>
</tbody>
</table>
</div>
)
}
export default TableRows
You should remove bracket
const TableDisplay = ({ rows }) => {
return (
<>
{rows.map((row) => <TableRows key={row.id} row={row} />)}
</>
);
};
or add return
const TableDisplay = ({ rows }) => {
return (
<>
{rows.map((row) => {
return <TableRows key={row.id} row={row} />;
})}
</>
);
};

How can I pass props to another components with in reactjs

I'm trying to pass product data from AllProducts component to Product component.
AllProducts.jsx: is showing all the products I have and Product.jsx will show specific product and how can I pass data to Product.jsx?
Here is my AllProducts.jsx:
const AllProducts = (props) => {
const [products, setProducts] = useState([]);
const getProductsAPI = () => {
axios
.get("http://localhost:8000/api/products")
.then((res) => {
setProducts(res.data);
getProductsAPI();
})
.catch((err) => {
console.log(err);
});
};
useEffect(() => {
getProductsAPI();
}, [props]);
return (
<div>
<table className="table table-bordered table-hover">
<thead>
<tr>
<th>#</th>
<th>Title</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{products.map((product, i) => (
<tr key={i}>
<th scope="row">{i}</th>
<td>{product.title}</td>
<td>
<Link to={`/products/${product._id}`}> View </Link>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
and here is my Product.jsx:
const Product = (props) => {
return (
<div className="container">
<h4>{props.product.title}</h4>
</div>
);
};
export default Product;
Here is my project github if you want to look at all the code I have: https://github.com/nathannewyen/full-mern/tree/master/product-manager
If the data is fully loaded for each product in AllProducts, and you don't want to make another API call by product id in the Product component, in this case, you don't have to use a route link to view Product, just make a conditional rendering to show Product component inside AllProducts component. pseudo-code as below,
const [showProduct, setShowProduct] = useState(false);
const [currentProduct, setCurrentProduct] = useState();
const showProduct = (product) => {
setShowProduct(true);
setCurrentProduct(product);
}
<tbody>
{products.map((product, i) => (
<tr key={i}>
<th scope="row">{i}</th>
<td>{product.title}</td>
<td>
<button type="button" onclick = {showProduct(product)}>View</button>
</td>
</tr>
))}
</tbody>
return (showProduct ? <Product /> : <AllProucts/>)
If you also need to make another API call to get extra data for each product, then use the router link but perhaps you can not pass props.

No access to "this"

I'm working on a web-application using the MERN stack that displays a table of clients with their name, email, and phone number. I haven't implemented Redux quite yet, but I'm using 'uuid' to supplement data in the table until I can get the redux store set up. So far I have displaying the the list and adding a client to the list working fine, but I am having trouble with the pesky delete button.
This is the current ClientTable component
import React, { Component } from "react";
import { Table, Container, Button } from "reactstrap";
import { connect } from "react-redux";
import {
getClients,
addClient,
editClient,
deleteClient,
} from "../actions/clientActions";
import PropTypes from "prop-types";
const renderClient = (clients, index, id) => {
return (
<tr key={index}>
<td>
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={() => {
this.setState((state) => ({
clients: state.clients.filter((client) => client.id !== id),
}));
}}
>
×
</Button>
</td>
<td>{clients.name}</td>
<td>{clients.email}</td>
<td>{clients.number}</td>
</tr>
);
};
class ClientTable extends Component {
componentDidMount() {
this.props.getClients();
}
onDeleteClick = (id) => {
this.props.deleteClient(id);
};
render() {
const { clients } = this.props.client;
// const { clients } = this.state;
return (
<Container id="listContainer">
<Table
id="listTable"
className="table-striped table-bordered table-hover"
dark
>
<tr class="listRow">
<thead id="tableHeader">
<tr>
<th id="listActions">Actions</th>
<th id="listName">Name</th>
<th id="listEmail">Email</th>
<th id="listNumber">Number</th>
</tr>
</thead>
<tbody class="listRow">{clients.map(renderClient)}</tbody>
</tr>
</Table>
</Container>
);
}
}
ClientTable.propTypes = {
getClients: PropTypes.func.isRequired,
client: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => ({
client: state.client,
});
export default connect(mapStateToProps, {
getClients,
deleteClient,
addClient,
})(ClientTable);
This is the bit of code that is causing me issues
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={() => {
this.setState((state) => ({
clients: state.clients.filter((client) => client.id !== id),
}));
}}
>
×
</Button>
When I click the "delete" button I keep getting TypeError: Cannot read property 'setState' of unedefined
I know the error is because of 'this' isn't bound to anything, but I'm uncertain how to bind it within an onClick event if that is even possible or what even to bind it to. I am just lost as to how to approach this problem. (I'm still quite new to React).
If anyone has any ideas it would be greatly appreciated!
move renderClient function to ClientTable, and use it as a method of this class.
class ClientTable extends Component {
componentDidMount() {
this.props.getClients();
}
renderClient = (clients, index) => {
return (
<tr key={index}>
<td>
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={() => this.onDeleteClient(clients.id)}
>
×
</Button>
</td>
<td>{clients.name}</td>
<td>{clients.email}</td>
<td>{clients.number}</td>
</tr>
);
};
onDeleteClick = (id) => {
this.props.deleteClient(id);
};
render() {
const { clients } = this.props.client;
// const { clients } = this.state;
return (
<Container id="listContainer">
<Table
id="listTable"
className="table-striped table-bordered table-hover"
dark
>
<tr class="listRow">
<thead id="tableHeader">
<tr>
<th id="listActions">Actions</th>
<th id="listName">Name</th>
<th id="listEmail">Email</th>
<th id="listNumber">Number</th>
</tr>
</thead>
<tbody class="listRow">{clients.map(this.renderClient)}</tbody>
</tr>
</Table>
</Container>
);
}
}

Refreshing sorted table in React and state issue

I tried to sort an array in React, but I don't know how to refresh it. If I set data in a state like this: (data: this.props.data) pagination isn't working. Why is that?
render() {
let data = this.props.data;
return (
<div className='container'>
<table>
<thead>
<tr>
<th>iD</th>
<th>First name</th>
<th>Last name</th>
<th>Birth date</th>
<th onClick={() => {data.sort()}}>Company</th>
<th>Note</th>
</tr>
</thead>
<tbody>
{data.map((user) => {
return (
<tr key={user.id}>
<td className="number">{user.id}</td>
<td className="firstname">{user.firstName}</td>
<td className="lastname">{user.lastName}</td>
<td className="date">{user.dateOfBirth}</td>
<td className="company">{user.company}</td>
<td className="note">{user.note}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
Check the code below
state = {
//use constructor or es7
data:this.props.data
}
_handleSort=()=>{
/**
* Define you short logic here.
*/
let sortedDate = this.state.data.dateOfBirth.sort()
this.setstate({
data:sortedDate
})
}
render() {
let {data} = this.state;
return (
<div className='container'>
<table>
<thead>
<tr>
<th>iD</th>
<th>First name</th>
<th>Last name</th>
<th>Birth date</th>
<th onClick={() => {this._handleSort}>Company</th>
<th>Note</th>
</tr>
</thead>
<tbody>
{data.map((user) => {
return (
<tr key={user.id}>
<td className="number">{user.id}</td>
<td className="firstname">{user.firstName}</td>
<td className="lastname">{user.lastName}</td>
<td className="date">{user.dateOfBirth}</td>
<td className="company">{user.company}</td>
<td className="note">{user.note}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
The best way of fix this problem is sort array in parent component.
Instesd of data.sort() you will call this.props.sort() property and your table component will be updated with sorted data.
render() {
let data = this.props.data;
return (
<div className='container'>
<table>
<thead>
<tr>
<th>iD</th>
<th>First name</th>
<th>Last name</th>
<th>Birth date</th>
<th onClick={this.props.sort}>Company</th>
<th>Note</th>
</tr>
</thead>
<tbody>
{data.map((user) => {
return (
<tr key={user.id}>
<td className="number">{user.id}</td>
<td className="firstname">{user.firstName}</td>
<td className="lastname">{user.lastName}</td>
<td className="date">{user.dateOfBirth}</td>
<td className="company">{user.company}</td>
<td className="note">{user.note}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
Parent :
class Parent extends Component {
constructor() {
super(props)
this.state = {
data: ....
}
}
sort = () => {
this.setState({
data: sortDataHere !!!!
})
}
render() {
return (
<Table
data={this.state.data}
sort={this.sort}
/>
)
}
}
Your component isn't properly controlled, since you're just using a reference obtained from props, which doesn't trigger render(). Components should instead be controlled on either state or props to trigger render() changes.
Here's an example to demonstrate that this pattern doesn't work:
class Example extends React.Component {
render () {
let text = this.props.data
return (
<div>
{text}
<button onClick={()=> (text='bye')}>
Click Me
</button>
</div>
)
}
}
ReactDOM.render(<Example data='hello' />, document.getElementById('container'))
<div id='container'></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
What you are trying to do is control the component. You have two main options:
1) A stateful approach:
constructor (props) {
super(props)
this.state = { data: props.data }
}
render () {
return (
<th onClick={() => {sortTable.bind(this)}}>Company</th>
)
}
sortTable () {
let { data } = this.state
// sort algorithm,
this.setState({ data })
}
2) A Stateless Pattern using props and something like Redux
This is usually the preferred methodology as it keeps components purely as presentation without logic, which tend to be more reusable.
class Example extends React.Component {
render () {
const { data } = this.props
return (
<th onClick={() => this.props.sortData(data)}>Company</th>
)
}
}
const mapStateToProps = (state) => {
return {
data: state.data
}
}
const mapDispatchToProps = (dispatch) => {
return {
sortData: data => {
dispatch({ type: SORT, payload: data })
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Example)
Then in a state reducer:
export default function (state, action) {
switch (action.type) {
case SORT:
// transform the data
}
}
I tried to keep this above example minimal, and as such it will not work as is. It purely demonstrates how the connected component might look. To fully use redux you need to setup your application with a <Provider> and a store.

Resources