React SetState and dispatch not working onClick function - reactjs

I hope that some one helps me i get Content-Range from server and transform the string to the pagination
For example : when i call
sitesActions.getAll()
My action returns
sites:
acceptRange:"10"
contentRange:"0-9/25"
data:(10) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}..]
Content-Range : 0-9/25
Accept-Range : 10 (The maximum collection returned)
These result makes me generate my pagination array like this example
Pagination Details function generate array of pagination
function paginationDetails(contentRange, acceptRange) {
console.log('content', contentRange);
let paginationDetails = contentRange.split("/");
let allCollection = parseInt(paginationDetails[1]);
let numberReturnedData = acceptRange;
let paginationNbr = Math.ceil(allCollection/numberReturnedData);
let rows = [{
pageNumber : 1 ,
startData : 0,
endData: numberReturnedData-1
}]
for (let i = 1; i < paginationNbr; i++) {
let end = (numberReturnedData-1)+(Number(i)*numberReturnedData);
rows.push(
{
pageNumber: Number(i)+1,
startData : numberReturnedData*Number(i),
endData: (end>allCollection) ? allCollection : end ,
}
);
}
console.log(rows);
return rows;
}
Array of pagination
[{pageNumber: 1, startData: 0, endData: 9}
{pageNumber: 2, startData: 10, endData: 19}
{pageNumber: 3, startData: 20, endData: 25}]
To make the pagination Componenet Global and reused in each component
i add to my parent component click={sitesActions.getAllWithRange}
Action Get all with range
function getAllWithRange(start, end) {
return dispatch => {
dispatch(request());
sitesService.rangeSites(start, end)
.then(
sites => dispatch(success(sites)),
error => {
dispatch(failure(error));
dispatch(alertActions.error('Error fetching site data'));
}
);
};
function request() { return { type: sitesConstants.SITES_REQUEST } }
function success(sites) { return { type: sitesConstants.SITES_SUCCESS, sites } }
function failure(error) { return { type: sitesConstants.SITES_FAILURE, error } }
}
so i dispatch this props and uses it in pagination using
dispatch(this.props.click(elementInfo.startData, elementInfo.endData));
Pagination Component
<PaginationManager
click={sitesActions.getAllWithRange}
paginationInfo={paginationDetails(sites.items.contentRange, sites.items.acceptRange)} />
</Aux>
Parent Component File
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {Aux} from '../hoc';
import {paginationDetails} from '../helpers';
import { sitesActions } from '../actions/sitesActions';
import classes from './BillsManager.css';
import PaginationManager from './PaginationManager';
class SitesManager extends Component {
componentDidMount() {
this.props.dispatch(sitesActions.getAll());
}
goToSite(siteLink) {
window.open('http://'+siteLink, '_blank');
}
render(){
const { sites } = this.props;
return(
<Aux>
<h1>Sites</h1>
<p>You can see all details of your sites.</p>
{sites.loading && <em>Loading sites...</em>}
{sites.items && <Aux>
<table className="table table-bordered">
<thead >
<tr>
<th>Site</th>
<th>Date</th>
<th>Status</th>
<th>Renew</th>
</tr>
</thead>
<tbody>
{sites.items.data.map((site, index) =>
<tr key={site.id}>
<th>{site.main_domain}</th>
<th>{site.CreatedTime}</th>
<th>{site.ps_status}</th>
<th className={classes.Link} onClick={() =>this.goToSite(site.main_domain)}><i className='fa fa-globe'></i></th>
</tr>
)}
</tbody>
</table>
<PaginationManager
click={sitesActions.getAllWithRange}
paginationInfo={paginationDetails(sites.items.contentRange, sites.items.acceptRange)} />
</Aux>
}
</Aux>
)
}
}
function mapStateToProps(state, ownProps) {
return {
sites : state.sites
};
}
export default connect(mapStateToProps)(SitesManager);
Pagination Component File
import React, {Component} from 'react'
import {connect} from 'react-redux';
class PaginationManager extends Component {
constructor(props) {
super(props)
this.state = {
activePage : this.props.paginationInfo[0],
activeIndex: 0
}
this.handleClick = this.handleClick.bind(this);
}
handleClick = (elementInfo, index) => {
const { dispatch } = this.props;
dispatch(this.props.click(elementInfo.startData, elementInfo.endData));
this.setState({
activePage : elementInfo,
activeIndex: index
})
}
render() {
let isDisabledPrevious = (this.state.activeIndex === 0) ? 'disabled' : '';
let isDisabledNext = (this.props.paginationInfo.length-1 === this.state.activeIndex) ? 'disabled' : '';
return ( <nav aria-label="Page navigation example">
<ul className="pagination justify-content-center">
<li className={`page-item ${isDisabledPrevious}`}>
<a className="page-link"
onClick={() => this.handleClick(this.props.paginationInfo[this.state.activeIndex-1]
,this.state.activeIndex-1)} >Previous</a>
</li>
{this.props.paginationInfo && this.props.paginationInfo.map((pageInfo, index) => {
return <li key={pageInfo.pageNumber} className={`page-item ${(this.state.activePage.pageNumber === pageInfo.pageNumber) ? 'active' : ''}` }>
<a className="page-link" onClick={() =>this.handleClick(pageInfo, index)} >{pageInfo.pageNumber}</a>
</li>
})
}
<li className={`page-item ${isDisabledNext}`}>
<a className="page-link"
onClick={() => this.handleClick(this.props.paginationInfo[this.state.activeIndex+1]
,this.state.activeIndex+1)} >Next</a>
</li>
</ul>
</nav>);
}
};
export default connect()(PaginationManager);
I was passing too much time trying to solve this problem , but i don't know why the setState don't work. The pagination works fine and the setState works and return the updated values just when i comment the dispatch(this.props.click(elementInfo.startData, elementInfo.endData));

Related

How to delete table row on button click in React

I wrote an application in React to get value from database, and display its elements in table. It works fine. But my problem is that when I click on delete button in addDelete function, it deletes the content not in the expected way ( I want to delete row sittuated previous to the button). I tryed most of approaches from stack overflow but it didn't work. Here's my code:
import './App.css';
import {Users} from "./users";
import {Email} from "./emails";
import React, {Component} from "react";
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
export class App extends Component{
constructor(props){
super(props);
this.state = {
users: [],
rows: [{}],
data: [],
products: []
};
this.addChild= this.addChild.bind(this);
}
componentDidMount() {
fetch('https://jsonplaceholder.typicode.com/users').then((Response) => Response.json())
.then((findresponse) =>
{
this.setState({
users:findresponse
})
//console.log(this.state.users);
});
}
addChild = (product) => {
if(this.state.products.indexOf(product.name) === -1){
this.setState({ products: [...this.state.products, product]})
}
}
addDelete = (i, j) => {
var items = this.state.users;
const index = items.indexOf(items[i]);
if (index > -1) {
items.splice(index, 1);
}
this.setState({
items: items
});
}
render(){
return (
<>
<div className="App">
<main>
<Users callback = {this.addChild} />
<table className = 'list1 table-sm table-striped'>
<thead><tr><th>Name and surname</th><th>Email address</th><th>Delete</th></tr></thead>
<tbody>
{ this.state.users.map(person=><tr className ='name1' key = {person.id}><td>
{person.name}
</td>
<td>
{person.email}
</td>
<td>
<button key = {person.id} onClick={this.addDelete.bind(null, person.id)} className="btn btn-danger btn-sm">Delete</button>
</td></tr>)}
{
this.state.person === 0
? <div className = 'text-center'>There is no persons</div>
: <Email key = {this.state.products.id} products = {this.state.products} />
}
</tbody>
</table>
</main>
</div>
</>
);
}
}
export default App;

how can i get the value of the clicked row in the handle button

you dont need to see the link and other component than table
import React, { Fragment } from "react";
import { connect } from "react-redux";
import { TradeStateData, loadTradeStateDataSocket } from "../../actions";
import io from "socket.io-client";
import { Menu , Button} from "semantic-ui-react";
import { Link } from "react-router-dom";
import AddModal from './AddModal';
import { ButtonToolbar } from "react-bootstrap";
// import App from "./app";
let columns = [
"ClientID",
"Algo",
"STOPER",
"Start/Stop Status",
"LossLimit",
"Quantity_Multiple",
"Trade Limit Per Day",
"Quantity Limit Per Trade",
"Lot Size",
"Slice Size",
"Wait Time",
"Trade Limit Per Second",
];
let socket;
// let status;
// let buy_sell_flag;
// let cancelrejectreason_flag;
class TradeState extends React.Component {
constructor(props) {
super(props);
this.state={
showModal:false
}
this.handlebutton = this.handlebutton.bind(this);
const { dispatch } = this.props;
// console.log(dispatch)
// console.log(this.props)
//socket = io.connect("http://192.168.0.103:5009");
socket = io.connect("http://192.168.43.179:5009");
dispatch(loadTradeStateDataSocket(socket));
socket.on("TradeStateToggler_data", (res) => {
dispatch(TradeStateData(res));
});
}
handlebutton = (algoname,clientid) => {
fetch("http://127.0.0.1:5000/updatetable", {
method: "POST",
headers: {
"Content-type": "application/json",
},
body: JSON.stringify({"algoname":algoname,"clientid":clientid}),
})
this.setState({showModal:false})
console.log("heyaaakomalu", {"algoname":algoname,"clientid":clientid});
};
toggle=()=>{
this.setState({showModal:true})
}
// componentWillUnmount() {
// socket.disconnect()
// console.log('Socket Disconnected')
// }
render() {
let closeModal=()=>this.setState({showModal:false})
// console.log(this.props)
return (
<Fragment>
<Menu style={{ margin: 0 }}>
<a href="tradestatetoggler">
<Menu.Item active={true}>ALL</Menu.Item>
</a>
<Link to="/d18138status">
<Menu.Item>D18138</Menu.Item>
</Link>
<Link to="/d7730001status">
<Menu.Item>D7730001</Menu.Item>
</Link>
<Link to="/d7730003status">
<Menu.Item>D7730003</Menu.Item>
</Link>
<Link to="/d7730004status">
<Menu.Item>D7730004</Menu.Item>
</Link>
<Link to="/d7730005status">
<Menu.Item>D7730005</Menu.Item>
</Link>
<Link to="/d7730006status">
<Menu.Item>D7730006</Menu.Item>
</Link>
<Link to="/d7730007status">
<Menu.Item>D7730007</Menu.Item>
</Link>
<Link to="/d7730008status">
<Menu.Item>D7730008</Menu.Item>
</Link>
<Link to="/d7730009status">
<Menu.Item>D7730009</Menu.Item>
</Link>
<Link to="/d8460002status">
<Menu.Item>D8460002</Menu.Item>
</Link>
<Link to="/d8460003status">
<Menu.Item>D8460003</Menu.Item>
</Link>
<Link to="/V7410004status">
<Menu.Item>V7410004</Menu.Item>
</Link>
</Menu>
**you can start watching here **
<table className="ui celled table">
<thead>
<tr>
{columns.map((col) => (
<th key={col}>{col}</th>
))}
</tr>
</thead>
<tbody>
{this.props.data.map((row) => {
// console.log(this.props.data);
// if (row.buy_sell === "BUY") buy_sell_flag = "positive";
// else buy_sell_flag = "negative";
// if (row.cancelrejectreason !== "")
// cancelrejectreason_flag = "negative";
// else cancelrejectreason_flag = "";
if (row.Start_Stop !== "STOP")
return (
<tr key={row._id}>
<td>{row.ClientID}</td>
<td>{row.algoname}</td>
<td>
<Button color="red" onClick={this.toggle}>STOP </Button>
<AddModal
show={this.state.showModal}
onHide={closeModal}
sendAll={()=>this.handlebutton(row.algoname,row.ClientID)}/>
**in this modal the value i want is of the clicked row but instead i am getting the value of the last rendered row **
</td>
<td>{row.Start_Stop}</td>
<td>{row.losslimit}</td>
<td>{row.quantity_multiple}</td>
<td>{row.TradeLimitPerDay}</td>
<td>{row.QuantityLimitPerTrade}</td>
<td>{row.lotSize}</td>
<td>{row.sliceSize}</td>
<td>{row.waitTime}</td>
<td>{row.tradeLimitPerSecond}</td>
</tr>
);
return null;
})}
</tbody>
</table>
</Fragment>
);
}
}
const MapStateToProps = (state) => {
// console.log(state);
let sortedstate = state.TradeState;
const sorted = {
data: sortedstate.sort((a, b) => b.ClientID.localeCompare(a.ClientID)),
};
return sorted;
};
export default connect(MapStateToProps)(TradeState);
how to get the current row value instead of last rendered row
addmodal contains just a normal modal. please help me with.
what you need to do is something like this. I don't know if your data item has a unique ID for each item. This is a way that you can do it
when you .map over your data you should always add a key prop to the first component that renders something like this
data.map((row) => {
return <div key={row._id}>{row._id}</div>
})
what you then should do is pass the data to your AddModal component like this.
<AddModal data={data[index]} />
this way your modal will only get the data that then user have clicked on.

react state is one state behind button clicks

I am writing a simple react page that renders 2 different html tables based off of which button is clicked on the screen. The issue I am having is that the table that is rendered for each button click is associated with the previous button click. (E.G. if I click button 1 one time then click button 2 the table associated with button 1 will be displayed.)
I am new to react so in order to get the tables to update I refactored my code to hold as much of the state as possible in the App.js class, I created the toggleState callback to associate the button clicks with state change of the parent, and I then pass that to DataProvider via the endpoint property. I realize this is probably where the state / UI disconnect is occurring, but I'm uncertain of the cause since I'm adhering to react principles to the best of my capability.
my class structure is as follows:
App
/ \
/ \
/ \
DataProvider ButtonToggle
|
Table
If it is relevant the table class is building the table based off of an API call, I will add the code for this, but it is not causing me problems so I do not believe it to be the source of the issue.
App.js
import React, { Component } from "react";
import PropTypes from "prop-types";
import DataProvider from "./DataProvider";
import Table from "./Table";
import ButtonToggle from "./ButtonToggle";
class App extends Component {
constructor(props){
super(props);
this.state = {
input : 'employees',
endpoint : "api/employees/"
};
console.log("constructor app: " + this.state.input + "\n" + this.state.endpoint);
}
toggleState(input) {
if(input == "employees") {
this.setState({input : input, endpoint: "api/employees/"});
}
else {
this.setState({input : input, endpoint: "api/categories/"});
}
console.log("toggleState " + this.state.input + "\n" + this.state.endpoint);
}
render() {
return (
<div className="col-lg-12 grid-margin">
<div className="card">
<div className="card-title">
<div className="row align-items-center justify-content-center">
<div className="col-3"></div>
<div className="col-6">
<h1> Striped Table</h1>
</div>
<div className="col-3"></div>
</div>
<ButtonToggle toggleInput={ (input) => this.toggleState(input)}/>
</div>
<div className="card">
<div className="card-title"></div>
<div className="card-body">
<DataProvider endpoint={this.state.endpoint}
render={data => <Table data={data} />} />
</div>
</div>
</div>
</div>
);
}
}
export default App;
DataProvider.js
class DataProvider extends Component {
static propTypes = {
endpoint: PropTypes.string.isRequired,
render: PropTypes.func.isRequired
};
constructor(props) {
super(props);
this.state = {
data: [],
loaded: false,
placeholder: "Loading..."
};
}
componentWillReceiveProps(props) {
console.log("dataprov: " + this.props.endpoint);
this.componentDidMount();
}
componentDidMount() {
fetch(this.props.endpoint)
.then(response => {
if (response.status !== 200) {
return this.setState({ placeholder: "Something went wrong" });
}
return response.json();
})
.then(data => this.setState({ data: data, loaded: true }));
}
render() {
const { data, loaded, placeholder } = this.state;
return loaded ? this.props.render(data) : <p>{placeholder}</p>;
}
}
export default DataProvider;
ButtonToggle.js
class ButtonToggle extends Component {
constructor (props) {
super(props);
}
render() {
return (
<div className="row align-items-center justify-content-center">
<div className="col-3 center-in-div">
<button type="button" className="btn btn-info btn-fw" onClick={this.props.toggleInput.bind(this, 'categories')}> Categories </button>
</div>
<div className="col-3 center-in-div">
<button type="button" className="btn btn-info btn-fw" onClick={this.props.toggleInput.bind(this, 'employees')}>
Employees
</button>
</div>
<div className="col-6"></div>
</div>
);
}
}
export default ButtonToggle;
Table.js : I don't think this is a problem, but I may stand corrected.
import React from "react";
import PropTypes from "prop-types";
import key from "weak-key";
const Table = ({ data }) =>
!data.length ? (
<p>Nothing to show. Records: {data.length} </p>
) : (
<div className="table-responsive">
<h2 className="subtitle">
Showing <strong>{data.length} items</strong>
</h2>
<table className="table table-hover">
<thead>
<tr>
{Object.entries(data[0]).map(el => <th key={key(el)}>{el[0]}</th>)}
</tr>
</thead>
<tbody>
{data.map(el => (
<tr key={el.id}>
{Object.entries(el).map(el => <td key={key(el)}>{el[1]}</td>)}
</tr>
))}
</tbody>
</table>
</div>
);
Table.propTypes = {
data: PropTypes.array.isRequired
};
export default Table;
Below is the minimum working code I could come up with. Your Button and Table components can be dumb components which will get data from parent component and will present it.
Your Parent or container component will have logic to set the properties for Button and Table component.
As Table and Button components are dumb you can go with functional components.
I have added the code for calling api (I have tried to mimic the api call) and getting data in same parent component, you can separate it out.
You can work on style and validations as per your needs.
Let me know if you need any further help.
class ParentComponent extends Component {
constructor() {
super();
this.state = {
name: "Category"
}
this.onBtnClick = this.onBtnClick.bind(this);
}
componentDidMount() {
this.getData(this.state.name)
}
getData(name) {
if (name === "Category") {
this.apiCall("/Category").then((data) => {
this.setState({ data: data })
})
} else {
this.apiCall("/Employee").then((data) => {
this.setState({ data: data })
})
}
}
apiCall(url) {
return new Promise((res, rej) => {
setTimeout(() => {
if (url === "/Employee") {
res([{ "Emp Name": "AAA", "Emp Age": "20" }, { "Emp Name": "BBB", "Emp Age": "40" }])
} else {
res([{ "Cat Id": "XXX", "Cat Name": "YYY" }, { "Cat Id": "MMM", "Cat Name": "NNN" }])
}
}, 1000)
});
}
onBtnClick(name) {
let newName = "Category"
if (name === newName) {
newName = "Employee"
}
this.setState({ name: newName, data: [] }, () => {
this.getData(newName);
})
}
render() {
return (<>
<ButtonComponent name={this.state.name} onBtnClick={this.onBtnClick}></ButtonComponent>
<TableComponent data={this.state.data} />
</>)
}
}
const ButtonComponent = ({ name, onBtnClick }) => {
return <Button onClick={() => { onBtnClick(name) }}>{name}</Button>
}
const TableComponent = ({ data }) => {
function getTable(data) {
return < table >
<thead>
<tr>
{getHeading(data)}
</tr>
</thead>
<tbody>
{getRows(data)}
</tbody>
</table >
}
function getHeading(data) {
return Object.entries(data[0]).map((key) => {
return <th key={key}>{key[0]}</th>
});
}
function getRows(data) {
return data.map((row, index) => {
return <tr key={"tr" + index}>
{Object.entries(data[0]).map((key, index) => {
console.log(row[key[0]]);
return <td key={"td" + index}>{row[key[0]]}</td>
})}
</tr>
})
}
return (
data && data.length > 0 ?
getTable(data)
: <div>Loading....</div>
)
}

Passing the value of page from Pagination.jsx to App.jsx

While I'm trying to get in to React, I started a project and got stuck. Maybe some one can help me to find the issue. Bellow I explain what the app should do.
The user types a query in an input-box inside SearchBar.jsx
The SearchBar component passes the query to App.jsx and fires up fetchPhotos function, which starts an API request.
To sort out pagination, the App.jsx imports Pagination.jsx, which calculates the number of pictures in the response and displays pagination buttons.
The above works.
But now if you click on a pagination button, the value for page from Pagination component should be passed to App.jsx and so to fetchPhotos function (runs the API request).
I guess the problem is that the value of page never finds its way to App.jsx and so the API request is missing the value of page.
I spent hours but couldn't find a way to fix it, due to lack of knowledge. Could you please point me to the right direction and show me what is wrong with the code?
App.jsx
import React, { Component } from "react";
import axios from "axios";
import Pagination from "../Pagination";
import SearchBar from "../SearchBar";
import ListItem from "../ListItem";
import "./app.scss";
class App extends Component {
state = {
photos: [],
totalPhotos: 0,
perPage: 30,
currentPage: 1,
query: null
};
componentDidMount() {
this.fetchPhotos("gorilla", this.state.currentPage);
}
fetchPhotos = (inputValue, page) => {
const baseUrl = "https://api.unsplash.com/search/photos";
const options = {
headers: {
Authorization: `Client-ID ${process.env.REACT_APP_UNSPLASH_API_KEY}`
},
params: {
query: inputValue,
page: this.state.page,
per_page: this.state.perPage
}
};
axios
.get(baseUrl, options)
.then(response => {
this.setState({
photos: response.data.results,
totalPhotos: parseInt(response.headers["x-total"]),
currentPage: page,
query: inputValue
});
})
.catch(() => {
console.log("Error");
});
};
render() {
return (
<div className="app">
<SearchBar onSubmit={this.fetchPhotos} />
<Pagination
current={this.state.currentPage}
total={this.state.totalPhotos}
perPage={this.state.perPage}
query={this.state.query}
onPageChanged={query => this.fetchPhotos(this.state.query)}
/>
<List data={this.state.photos} />
</div>
);
}
}
const List = ({ data }) => {
var items = data.map(photo => <ListItem key={photo.id} photo={photo} />);
return <div className="grid">{items}</div>;
};
export default App;
SearchBar.jsx
import React, { Component } from "react";
class SearchBar extends Component {
state = {
inputValue: ""
};
handleFormSubmit = e => {
e.preventDefault();
this.props.onSubmit(this.state.inputValue);
};
render() {
return (
<div className="header">
<h1>Search for images on Unsplash</h1>
<form onSubmit={this.handleFormSubmit} className="ui form">
<input
type="text"
placeholder="Type here to search for images"
value={this.state.inputValue}
onChange={e => this.setState({ inputValue: e.target.value })}
/>
</form>
</div>
);
}
}
export default SearchBar;
Pagination.jsx
import React, { Component } from "react";
class Pagination extends Component {
pages() {
var pages = [];
for (var i = this.rangeStart(); i <= this.rangeEnd(); i++) {
pages.push(i);
}
return pages;
}
rangeStart() {
var start = this.props.current - this.props.pageRange;
return start > 0 ? start : 1;
}
rangeEnd() {
var end = this.props.current + this.props.pageRange;
var totalPages = this.totalPages();
return end < totalPages ? end : totalPages;
}
totalPages() {
return Math.ceil(this.props.total / this.props.perPage);
}
nextPage() {
return this.props.current + 1;
}
prevPage() {
return this.props.current - 1;
}
hasFirst() {
return this.rangeStart() !== 1;
}
hasLast() {
return this.rangeEnd() < this.totalPages();
}
hasPrev() {
return this.props.current > 1;
}
hasNext() {
return this.props.current < this.totalPages();
}
changePage(page) {
this.props.onPageChanged(page);
console.log("Page inside Pagination", page);
}
render() {
return (
<div className="pagination">
<div className="pagination__left">
<span
role="button"
className={!this.hasPrev() ? "hidden" : ""}
onClick={e => this.changePage(this.prevPage())}
>
Prev
</span>
</div>
<div className="pagination__mid">
<ul>
<li className={!this.hasFirst() ? "hidden" : ""}>
<span role="button" onClick={e => this.changePage(1)}>
1
</span>
</li>
<li className={!this.hasFirst() ? "hidden" : ""}>...</li>
{this.pages().map((page, index) => {
return (
<li key={index}>
<span
role="button"
onClick={e => this.changePage(page)}
className={this.props.current === page ? "current" : ""}
>
{page}
</span>
</li>
);
})}
<li className={!this.hasLast() ? "hidden" : ""}>...</li>
<li className={!this.hasLast() ? "hidden" : ""}>
<span
role="button"
onClick={e => this.changePage(this.totalPages())}
>
{this.totalPages()}
</span>
</li>
</ul>
</div>
<div className="pagination__right">
<span
className={!this.hasNext() ? "hidden" : ""}
onClick={e => this.changePage(this.nextPage())}
>
Next
</span>
</div>
</div>
);
}
}
Pagination.defaultProps = {
pageRange: 2
};
export default Pagination;
I think your error is at `onChange', because you are giving current state query to fetch instead of the new query:
onPageChanged={query => this.fetchPhotos(this.state.query)}
You should replace it for new query like:
onPageChanged={query => this.fetchPhotos(query)}
EDIT 1:
You can see working it on https://codesandbox.io/s/9ymjj8ko9p?fontsize=14.
The changes is just as I said, on App.jsx:
params fixed passing page from function params and not from
fix onPageChange prop to Pagination like:
onPageChanged={page => this.fetchPhotos(this.state.query, page)}

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.

Resources