I am trying to re render a component. I have a refresh button and I want to clean all filters and sorting values when clicked.
The thing is that I can not make a re render, not even with forceUpdate(), it is doing NOTHING and I don't know why. Also, I tried with setState(), and nothing. What I want to happen is what happens when I change the page, it re renders the component. Please can anybody could help me? What am I doing wrong?
import React, { Component } from "react";
import DeleteComponent from "../components/DeleteComponent"
import ReactTable from 'react-table';
import { Link, withRouter } from 'react-router-dom';
import axios from "axios";
import { getJwt } from '../helpers/jwt'
import eye from '../img/eye.png'
import bin from '../img/bin.png'
import writing from '../img/writing.png'
class CustomReactTable extends Component {
constructor(props) {
super(props)
this.state = {
data: [],
showDelete: false,
item: null,
pages: null,
totalItems: null,
loading: false,
state: {},
}
}
fetchData = (state) => {
this.setState({ state: state })
const jwt = getJwt()
if (!jwt) {
this.props.history.push('/login')
}
let config = {
headers: { 'Authorization': `Bearer ${jwt}` },
params: {
page: state.page,
pageSize: state.pageSize,
sorted: state.sorted,
filtered: state.filtered
}
}
this.setState({ loading: true })
axios.get(`http://localhost:3001/api/v1${this.props.location.pathname}`, config)
.then(response => {
console.log(response)
this.setState({
data: response.data.result,
loading: false
})
})
axios.get(`http://localhost:3001/api/v1${this.props.location.pathname}/count-documents`, config)
.then(response => {
this.setState({
totalItems: response.data.result,
pages: Math.ceil(response.data.result / state.pageSize)
})
})
}
loadOptions = () => {
this.props.columns.push({
Header: "",
Cell: (row) => [
// Find a better way to add unique key
<Link to={`${this.props.location.pathname}/${row.original._id}/show`} key={row.original._id} params={{ id: row.original._id }}><button className="btn-xs btn-outline-light"><img style={{ width: '1em' }} src={eye} /></button></Link>,
<Link to={`${this.props.location.pathname}/${row.original._id}/edit`} key={row.original._id + 'a'}><button className="btn-xs btn-outline-light"><img style={{ width: '1em' }} src={writing} /></button></Link>,
<button key={row.original._id + 'b'} className="btn-xs btn-outline-light" onClick={() => { this.onClickDeleteButton(row.original._id) }}><img style={{ width: '1em' }} src={bin} /></button>
]
})
}
loadFunctionalities = () => {
return (
<div className='functionalities-react-table'>
<span className='functionalities-add-item-table'>
<Link to={`${this.props.location.pathname}/add`}><button className="btn-sm btn-outline-success">Add new {this.props.modelName}</button></Link>
</span>
<span className='functionalities-refresh-table'>
<button className="btn-sm btn-outline-dark">Refresh table</button>
</span>
</div>
)
}
onClickDeleteButton = (id) => {
this.setState({ showDelete: true, item: id })
}
onCancelDeleteClick = () => {
this.setState({ showDelete: false })
}
componentDidMount() {
this.loadOptions()
}
reloadData = () => {
this.fetchData(this.state.state)
}
render() {
return (
<div className='main-content'>
{this.state.showDelete && (
<DeleteComponent reloadData={this.reloadData} onCancelDeleteClick={this.onCancelDeleteClick} item={this.state.item} />
)}
<h3>{`${this.props.modelName} (${this.state.totalItems})`}</h3>
{this.loadFunctionalities()}
<ReactTable
data={this.state.data}
columns={this.props.columns}
manual
onFetchData={this.fetchData}
defaultPageSize={10}
pages={this.state.pages}
style={{ fontSize: '0.9em' }}
>
</ReactTable>
<div className="total-records-tag">{this.props.modelName}: {this.state.totalItems}</div>
</div >
)
}
}
export default withRouter(CustomReactTable);
Related
I'm creating a custom Formio app using React and I'm trying to create a component that we can use to open previously created forms for editing. I use the component from Formio, and then try to pull the components and pass them to the components attribute, but it keeps telling me it's undefined. However, if I stringify it, and even import it using a variable or paste the exact string in, it works, but if I try to pass it to a variable or state, it won't work. Below is my code and any help is much appreciated. I feel like I've tried everything.
import { FormEdit, FormBuilder } from "react-formio";
import axios from "axios";
import AppLayout from "../pages/layout/appLayout";
import { Typography } from "#material-ui/core/";
import { Link } from "react-router-dom";
import { components } from "../formData";
export default class FormUpdate extends React.Component {
state = {
formName: "",
formTitle: "",
isFormSubmitted: false,
formComponents: {},
errorMsg: "",
};
componentDidMount() {
console.log("Id", this.props.formData);
axios
.get(
`https://awsid.execute-api.us-east-1.amazonaws.com/prod/form?formName=${this.props.formData.id}`,
{ crossDomain: true },
{
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,POST,OPTIONS",
},
}
)
.then((res) => {
console.log(res.data.form.components);
this.setState({
formComponents: res.data.form.components[0],
});
})
.catch((error) => {
console.log(error);
this.setState({ errorMsg: "Error retrieving form data." });
});
}
updateForm = (form) => {
const payload = {
form,
};
console.log("Form Data:", form);
/* Code to fix JSON of select boxes component. If no default value is selected, default value attribute is deleted */
for (var key in payload.form.components) {
if (
form.components[key].defaultValue === "" ||
form.components[key].defaultValue === null ||
// form.components[key].defaultValue === false ||
form.components[key].defaultValue.hasOwnProperty("")
) {
console.log(
form.components[key].defaultValue + " is blank. Deleting attribute."
);
delete form.components[key].defaultValue;
}
console.log(form.components[key].defaultValue);
}
return axios
.put(
`https://awsid.execute-api.us-east-1.amazonaws.com/prod/form`,
payload,
{ crossdomain: true },
{
headers: {
"Content-type": "application/json",
},
}
)
.then((response) => {
console.log("Uploaded", response.data);
this.setState({
formName: response.data.id,
formTitle: response.data.title,
isFormSubmitted: true,
});
})
.catch((error) => {
console.log("Did not post: " + error);
});
};
handleFormNameChange = (evt) => {
const value = evt.target.value;
this.setState({
...this.state,
formName: value,
});
};
handleFormNameClick = async () => {
await this.setState({
formNameForm: false,
});
this.retrieveData(this.state.formName);
// console.log(this.state.formName);
};
listComponents = () => {
this.state.formComponents.map((item) => {
console.log(item);
// this.setState({ formComponents: item });
return item;
});
};
components = JSON.stringify(this.state.formComponents).replace(
/^\[(.+)\]$/,
"$1"
);
render() {
// const components = JSON.stringify(this.state.formComponents).replace(
// /^\[(.+)\]$/,
// "$1"
// );
// const allComponents = this.state.formComponents[0];
console.log(
JSON.stringify(this.state.formComponents).replace(/^\[(.+)\]$/, "$1")
);
console.log(this.state.formComponents);
console.log(components);
return (
<AppLayout>
<div className="container">
<link rel="stylesheet" href="styles.css" />
<link
rel="stylesheet"
href="https://unpkg.com/formiojs#latest/dist/formio.full.min.css"
/>
<link
href="https://fonts.googleapis.com/css2?family=Bangers&display=swap"
rel="stylesheet"
></link>
<main className="formEditContainer">
{this.state.isFormSubmitted === true ? (
<div className="fadePanel">
<Typography variant="h4" align="center">
Form Completed
</Typography>
<br />
<Typography variant="body1" align="center">
<b>
<i> To view form visit:</i>
</b>{" "}
<Link
to={`/openform/${this.state.formName}`}
className="links"
>
<small>{this.state.formTitle}</small>
</Link>
</Typography>
</div>
) : (
<div>
<Typography>
Form Name:
{this.props.formData.id}
</Typography>
<br />
<FormEdit
form={{
display: "form",
title: this.props.formData.id,
name: this.props.formData.id,
path: this.props.formData.id,
components: [components],
}}
saveText={"Save Form"}
saveForm={(form) => this.updateForm(form)}
>
<FormBuilder
form={{
display: "form",
title: this.props.formData.id,
}}
Builder={{}}
onUpdateComponent={{}}
/>
</FormEdit>
</div>
)}
<br />
<br />
</main>
</div>
</AppLayout>
);
}
}
I am using reactjs. I am using the material-table to get the data with the editable table.
But I get an error like the picture, how can I fix this error?
I use useState for the edit settings of the table.
Please can you help with the error?
I do not receive any errors while receiving data. I just use editing on the table as active / inactive.
But
const [, forceUpdate] = useState (false);
const [data, setData] = useState (drBounty);
gives error for lines.
screenshot of the error and my source code below
import React, { Component, useState } from "react";
import withAuth from "../../components/helpers/withAuth";
import AlertMessageBox from "../../components/helpers/AlertMessageBox";
import { connect } from "react-redux";
import { Button, Col, Row, Table, Input } from "reactstrap";
import MaterialTable, { MTableEditRow } from "material-table";
import icons from '#material-ui/core/Icon';
import DeleteOutline from '#material-ui/icons/DeleteOutline';
import Edit from '#material-ui/icons/Edit';
class Bounty extends Component {
constructor(props) {
super(props);
this.state = {
isLoaded: true,
drBounty: [],
drList: [],
columns: [
{ title: 'Name', field: 'doctorName',
cellStyle:{padding: "1px", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", maxWidth: "1px"},
editComponent: (props) => (
<Input
type="text"
placeholder={props.columnDef.title}
defaultValue={props.value}
onChange={(e) => props.onChange(
this.setState({
doctorName: e.target.value
})
)}
/>
)
},
{ title: 'LastName', field: 'doctorLastName',
cellStyle:{padding: "1px", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", maxWidth: "5px"},
editComponent: (props) => (
<Input
type={"text"}
placeholder={"Doktor soyadı"}
defaultValue={props.value}
onChange={(e) => props.onChange(
this.setState({
doctorLastName: e.target.value
})
)}
/>
)
}
]
};
this.getBountyList = this.getBountyList.bind(this);
}
async componentDidMount() {
await fetch(
`${this.domain}/api/user/groupusers?groupCode=`+
this.props.account_profile.profile.profile.groupCode,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("id_token")}`,
"Content-Type": "application/json"
}
}
)
.then(res => {
if (res.ok) {
return res.json();
} else {
return res.json().then(err => Promise.reject(err));
}
})
.then(json => {
console.log(json)
})
.catch(error => {
console.log(error)
return error;
});
}
async getBountyList(id) {
await fetch(`${this.domain}/api/bounty/list?groupCode=${this.props.account_profile.profile.profile.groupCode}&doctor=${id}`,{
headers: {
Authorization: `Bearer ${localStorage.getItem("id_token")}`,
"Content-Type": "application/json"
}
})
.then(res => {
console.log(res);
if (res.ok) {
return res.json();
} else {
return res.json().then(err => Promise.reject(err));
}
})
.then(json => {
console.log(json)
})
.catch(error => {
console.log(error);
return error;
});
}
render() {
const {isLoaded, drList, drBounty} = this.state;
const [, forceUpdate] = useState(false);
const [data, setData] = useState(drBounty);
const isRowUpdating = (rowData, status) => {
rowData.tableData.editing = status ? "update" : undefined;
forceUpdate(status);
};
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div className={"animated fadeIn "}>
<Row>
<div> </div>
<Col sm={{span:1, offset:0.9}}>
<Table>
<thead>
<tr>
<th width={"20"} />
<th width={"50"}>Adı</th>
<th width={"70"}>Soyadı</th>
</tr>
</thead>
<tbody>
{
drList
.map(item => (
<tr key={item.id}>
<td>
<Button
block
outline
color="info"
onClick={() => this.getBountyList(item.id)}
>
Aç
</Button>
</td>
<td>{item.first_name} </td>
<td>{item.last_name}</td>
</tr>
))}
</tbody>
</Table>
</Col>
<MaterialTable
Icons={icons}
style={{height: "50", width: "50"}}
columns={ this.state.columns }
data={ this.state.drBounty }
actions={[
rowData => ({
icon: Edit,
tooltip: "Edit row",
onClick: (event, rowData) => {
isRowUpdating(rowData, true);
this.setState({
id: rowData.id,
user: rowData.user,
doctor: rowData.doctor,
doctorName: rowData.doctorName,
doctorLastName: rowData.doctorLastName,
totalBounty: rowData.totalBounty,
description: rowData.description,
customerName: rowData.customerName,
bountyDate: rowData.bountyDate,
createdDate: rowData.createdDate,
groupCode: rowData.groupCode
});
}
})
]}
components={{
EditRow: props => {
const newRowData = {
...drBounty, // *MUST INCLUDE tableData FROM ORIGINAL props.data!!*
id: "DEFAULT VALUES", // <-- // Set whatever default data you want here
doctorName: "ON EDIT" // <-- // (or pull from state, etc.. whatever you want)
};
return (
<MTableEditRow
{...props}
data={newRowData}
onEditingCanceled={(mode, rowData) => {
isRowUpdating(rowData, false);
}}
onEditingApproved={(mode, newData, oldRowData) => {
const dataCopy = [...drBounty];
const index = drBounty.indexOf(props.data);
dataCopy[index] = newData;
setData(dataCopy);
isRowUpdating(props.data, false);
}}
/>
);
}
}}
/>
</Row>
</div>
);
}
}
}
export default connect(withAuth( Bounty ));
You are trying to use the Hook (useState()) inside the render() method. Hooks can only be used inside of function components. However, you are using a class component so you have no need of this Hook.
Suggested Reading: https://reactjs.org/docs/hooks-state.html
Instead of using a Hook, you can use the following in your class component to accomplish the same results. Let's have a look :)
Initialize State in Constructor
this.state = { foo: bar };
You have already done this!
Update State with this.setState()
const [data, setData] = useState(drBounty);
Becomes ..
this.setState({data:drBounty});
However, you want to update the drBounty prop that you set up in the constructor, so you will want something more like this ..
this.setState({drBounty:someData})
Since that prop is an array, you will most likely want to spread (...) that data using the current array.
Re-Render without Updating State
As for your other implementation of useState() it appears you want to re-render without making any updates to state.
const [, forceUpdate] = useState(false);
However, instead you will want to simply use ...
this.render()
The code below shows each user info on users list button click.
Now I want fetch each users record from database on users list button click.
In the open() function, I have implemented the code below
open = (id,name) => {
alert(id);
alert(name);
//start axios api call
const user_data = {
uid: 'id',
uname: 'name'
};
this.setState({ loading_image: true }, () => {
axios.post("http://localhost/data.php", { user_data })
.then(response => {
this.setState({
chatData1: response.data[0].id,
chatData: response.data,
loading_image: false
});
console.log(this.state.chatData);
alert(this.state.chatData1);
})
.catch(error => {
console.log(error);
});
});
}
In class OpenedUser(), I have initialize in the constructor the code below
chatData: []
In the render method have implemented the code
<b> Load Message from Database for each user ({this.state.chatData1})</b>
<div>
{this.state.chatData.map((pere, i) => (<li key={i}>{pere.lastname} - {pere.id}----- {pere.username}</li>))}
</div>
Here is my Issue:
My problem is that the Axios Api is getting the result but am not seeing any result in the render method.
but I can see it in the console as per code below
Array(1)
0: {id: "1", firstname: "faco", lastname: "facoyo"}
length: 1
Here is an example of json api response.
[{"id":"1","firstname":"faco","lastname":"facoyo"}]
Here is the full code
import React, { Component, Fragment } from "react";
import { render } from "react-dom";
import { Link } from 'react-router-dom';
import axios from 'axios';
class User extends React.Component {
open = () => this.props.open(this.props.data.id, this.props.data.name);
render() {
return (
<React.Fragment>
<div key={this.props.data.id}>
<button onClick={() => this.open(this.props.data.id,this.props.data.name)}>{this.props.data.name}</button>
</div>
</React.Fragment>
);
}
}
class OpenedUser extends React.Component {
constructor(props) {
super(props);
this.state = {
chatData: [],
hidden: false,
};
}
componentDidMount(){
} // close component didmount
toggleHidden = () =>
this.setState(prevState => ({ hidden: !prevState.hidden }));
close = () => this.props.close(this.props.data.id);
render() {
return (
<div key={this.props.data.id} style={{ display: "inline-block" }}>
<div className="msg_head">
<button onClick={this.close}>close</button>
<div>user {this.props.data.id}</div>
<div>name {this.props.data.name}</div>
{this.state.hidden ? null : (
<div className="msg_wrap">
<div className="msg_body">Message will appear here</div>
<b> Load Message from Database for each user ({this.state.chatData1}) </b>
<div>
{this.state.chatData.map((pere, i) => (
<li key={i}>
{pere.lastname} - {pere.id}----- {pere.username}
</li>
))}
</div>
</div>
)}
</div>
</div>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
shown: true,
activeIds: [],
data: [
{ id: 1, name: "user 1" },
{ id: 2, name: "user 2" },
{ id: 3, name: "user 3" },
{ id: 4, name: "user 4" },
{ id: 5, name: "user 5" }
],
};
}
toggle() {
this.setState({
shown: !this.state.shown
});
}
open = (id,name) => {
alert(id);
alert(name);
//start axios api call
const user_data = {
uid: 'id',
uname: 'name'
};
this.setState({ loading_image: true }, () => {
axios.post("http://localhost/apidb_react/search_data.php", { user_data })
.then(response => {
this.setState({
chatData1: response.data[0].id,
chatData: response.data,
loading_image: false
});
console.log(this.state.chatData);
alert(this.state.chatData1);
})
.catch(error => {
console.log(error);
});
});
// end axios api call
this.setState((prevState) => ({
activeIds: prevState.activeIds.find((user) => user === id)
? prevState.activeIds
: [...prevState.activeIds, id]
}));
}
close = id => {
this.setState((prevState) => ({
activeIds: prevState.activeIds.filter((user) => user !== id),
}));
};
renderUser = (id) => {
const user = this.state.data.find((user) => user.id === id);
if (!user) {
return null;
}
return (
<OpenedUser key={user.id} data={user} close={this.close}/>
)
}
renderActiveUser = () => {
return (
<div style={{ position: "fixed", bottom: 0, right: 0 }}>
{this.state.activeIds.map((id) => this.renderUser(id)) }
</div>
);
};
render() {
return (
<div>
{this.state.data.map(person => (
<User key={person.id} data={person} open={this.open} />
))}
{this.state.activeIds.length !== 0 && this.renderActiveUser()}
</div>
);
}
}
The problem is you're making the request in the App component and storing in state but you're trying to access the state in a child component so it will never actually read the data.
To fix this you need to pass in the chat data via prop
<OpenedUser
chatData={this.state.chatData}
key={user.id}
data={user}
close={this.close}
/>
Note: In my runnable example, I've replaced your api endpoint with a mock api promise.
const mockApi = () => {
return new Promise((resolve, reject) => {
const json = [{ id: "1", firstname: "faco", lastname: "facoyo" }];
resolve(json);
});
};
class User extends React.Component {
open = () => this.props.open(this.props.data.id, this.props.data.name);
render() {
return (
<React.Fragment>
<div key={this.props.data.id}>
<button
onClick={() => this.open(this.props.data.id, this.props.data.name)}
>
{this.props.data.name}
</button>
</div>
</React.Fragment>
);
}
}
class OpenedUser extends React.Component {
constructor(props) {
super(props);
this.state = {
hidden: false
};
}
componentDidMount() {} // close component didmount
toggleHidden = () =>
this.setState(prevState => ({ hidden: !prevState.hidden }));
close = () => this.props.close(this.props.data.id);
render() {
return (
<div key={this.props.data.id} style={{ display: "inline-block" }}>
<div className="msg_head">
<button onClick={this.close}>close</button>
<div>user {this.props.data.id}</div>
<div>name {this.props.data.name}</div>
{this.state.hidden ? null : (
<div className="msg_wrap">
<div className="msg_body">Message will appear here</div>
<b>
{" "}
Load Message from Database for each user ({this.state.chatData1}
){" "}
</b>
<ul>
{this.props.chatData.map((pere, i) => (
<li key={i}>
{pere.lastname} - {pere.id}----- {pere.username}
</li>
))}
</ul>
</div>
)}
</div>
</div>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
shown: true,
chatData: [],
activeIds: [],
data: [
{ id: 1, name: "user 1" },
{ id: 2, name: "user 2" },
{ id: 3, name: "user 3" },
{ id: 4, name: "user 4" },
{ id: 5, name: "user 5" }
]
};
}
toggle() {
this.setState({
shown: !this.state.shown
});
}
open = (id, name) => {
alert(id);
alert(name);
//start axios api call
const user_data = {
uid: "id",
uname: "name"
};
// this.setState({ loading_image: true }, () => {
// axios
// .post("http://localhost/apidb_react/search_data.php", { user_data })
// .then(response => {
// this.setState({
// chatData1: response.data[0].id,
// chatData: response.data,
// loading_image: false
// });
// console.log(this.state.chatData);
// alert(this.state.chatData1);
// })
// .catch(error => {
// console.log(error);
// });
// });
this.setState({ loading_image: true }, () => {
mockApi().then(data => {
this.setState({
chatData1: data[0].id,
chatData: data,
loading_image: false
});
});
});
// end axios api call
this.setState(prevState => ({
activeIds: prevState.activeIds.find(user => user === id)
? prevState.activeIds
: [...prevState.activeIds, id]
}));
};
close = id => {
this.setState(prevState => ({
activeIds: prevState.activeIds.filter(user => user !== id)
}));
};
renderUser = id => {
const user = this.state.data.find(user => user.id === id);
if (!user) {
return null;
}
return (
<OpenedUser
chatData={this.state.chatData}
key={user.id}
data={user}
close={this.close}
/>
);
};
renderActiveUser = () => {
return (
<div style={{ position: "fixed", bottom: 0, right: 0 }}>
{this.state.activeIds.map(id => this.renderUser(id))}
</div>
);
};
render() {
return (
<div>
{this.state.data.map(person => (
<User key={person.id} data={person} open={this.open} />
))}
{this.state.activeIds.length !== 0 && this.renderActiveUser()}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I see a few missing points in your code namely you are using li without ul which is a kind of invalid markup, then you have mapping for .username which is undefined field according to response which may also throw error.
The photo object is not changing in the Gallery component via state.
I created a "folder gallery", a multi gallery component to render a new one if you select it by click.
See the demonstration:
https://codesandbox.io/s/50wr02n8q4
github issue:
https://github.com/neptunian/react-photo-gallery/issues/118
Envs:
react-photo-gallery: 6.2.2
react: 16.6.3
npm: 6.4.1
See the code below:
const folderPhotos = [
{
title: "Gallery one",
photos: [
{
src: "https://source.unsplash.com/2ShvY8Lf6l0/800x599"
},
{
src: "https://source.unsplash.com/Dm-qxdynoEc/800x799"
},
{
src: "https://source.unsplash.com/qDkso9nvCg0/600x799"
}
]
},
{
title: "Gallery two",
photos: [
{
src: "https://source.unsplash.com/iecJiKe_RNg/600x799"
},
{
src: "https://source.unsplash.com/epcsn8Ed8kY/600x799"
},
{
src: "https://source.unsplash.com/NQSWvyVRIJk/800x599"
}
]
}
];
The photoProps dimensions object:
const photoProps = {
width: 1,
height: 1
};
The internal component here:
<Gallery
columnsLength={6}
photosObj={folderPhotos}
photoProps={photoProps}
withLightbox={true}
/>
Now the Gallery component:
import _ from "lodash";
import React, { Component, Fragment } from "react";
import Gallery from "react-photo-gallery";
import Lightbox from "react-images";
export class PhotoGallery extends Component {
constructor(props) {
super(props);
// Bindables
this.showGallery = this.showGallery.bind(this);
this.openLightbox = this.openLightbox.bind(this);
this.closeLightbox = this.closeLightbox.bind(this);
this.goToPrevious = this.goToPrevious.bind(this);
this.goToNext = this.goToNext.bind(this);
}
state = {
photosObj: [],
currentImage: 0,
lightboxIsOpen: false
};
async showGallery(itemObj, photoProps) {
let photosObj = [];
if (!_.isEmpty(itemObj)) {
photosObj = await Object.keys(itemObj)
.map(i => itemObj[i])
.map(item => ({
...item,
width: photoProps.width,
height: photoProps.height
}));
this.setState({
photosObj
});
console.log("-- props: ", this.state.photosObj);
}
}
openLightbox(event, obj) {
this.setState({
currentImage: obj.index,
lightboxIsOpen: true
});
}
closeLightbox() {
this.setState({
currentImage: 0,
lightboxIsOpen: false
});
}
goToPrevious() {
this.setState({
currentImage: this.state.currentImage - 1
});
}
goToNext() {
this.setState({
currentImage: this.state.currentImage + 1
});
}
render() {
const { columnsLength, photosObj, photoProps, withLightbox } = this.props;
return (
<div className="section-body">
<div className="content-col-info">
<ul className="list-mentors w-list-unstyled">
{photosObj.map((itemObj, i) => (
<li key={i}>
<span
className="mentors-item w-inline-block"
onClick={() => this.showGallery(itemObj.photos, photoProps)}
>
<div>{itemObj.title}</div>
</span>
</li>
))}
</ul>
</div>
<div className="content-col-info">
{!_.isEmpty(this.state.photosObj) && (
<Gallery
columns={columnsLength}
photos={this.state.photosObj}
onClick={withLightbox ? this.openLightbox : null}
/>
)}
{!_.isEmpty(this.state.photosObj) && withLightbox && (
<Lightbox
images={this.state.photosObj}
onClose={this.closeLightbox}
onClickPrev={this.goToPrevious}
onClickNext={this.goToNext}
currentImage={this.state.currentImage}
isOpen={this.state.lightboxIsOpen}
/>
)}
</div>
</div>
);
}
}
export default PhotoGallery;
EDIT - I updated the Gallery props
I fix the Gallery component props of the example too.
loadGallery(columnsLength) {
import("./photo-gallery").then(Gallery => {
console.log("-- load gallery: ", this.state.photosObj);
return (
<Gallery.default
columnsLength={columnsLength}
photosObj={this.state.photosObj}
withLightbox={true}
/>
);
});
}
And to call this:
{!_.isEmpty(this.state.photosObj) && this.loadGallery(columnsLength)}
References:
Intro to Dynamic import() in Create React App
React images
Since photos option is required in Gallery.js (Library)
Gallery.propTypes = {
photos: _propTypes2.default.arrayOf(_Photo.photoPropType).isRequired,
direction: _propTypes2.default.string,
onClick: _propTypes2.default.func,
columns: _propTypes2.default.number,
margin: _propTypes2.default.number,
ImageComponent: _propTypes2.default.func
};
Pass "photos={this.state.photosObj}" in <Gallery /> of Gallery.js (your js file) as follows:
Code:
<Gallery
columnsLength={columnsLength}
photosObj={this.state.photosObj}
photos={this.state.photosObj}
withLightbox={true}
/>
I am not sure why you pass other options.
I have 3 records in my table, I can see the app fetches record to my remote because I console.log the response. My problem is that it will not display the item.
I know I defined correctly the column in FlatList because If I will set the per_page=1 which means pull 1 record every request. It will display but 2 records only will display the last record will not, if I set to per_page=30 nothing displays. is there a problem in my setState() during the response ?.I heard that setSate is not mutable..how can I apply the updater function of setsate in my code.?...I am still fresh on react native I hope someone will help me here.
I tried to do this but no luck!..also is this will matter that I use react-redux in my other page then in this screen I did not use only handling of state. ?...please help me react-native experts.
this.setState({
page: this.getParameterByName('page', res.next_page_url),
data: this.state.page === 1 ? res.data : [...this.state.data, ...res.data],
error: res.error || null,
loading: false,
refreshing: false,
last_page: res.last_page
},()=>{
return this.state;
});
Here is my complete code
import React, { Component } from 'react';
import {ScrollView, Text, View, Button, FlatList, ActivityIndicator} from 'react-native';
import { List, ListItem, Icon } from "react-native-elements";
import {connect} from "react-redux";
import numeral from "numeral";
import Moment from 'react-moment';
import moment from 'moment';
class Screen1 extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
page: 1,
per_page: 30,
order_by:'id',
sort_by:'asc',
error: null,
refreshing: false,
param:'',
last_page:''
};
}
componentDidMount() {
this.makeRemoteRequest();
}
makeRemoteRequest = () => {
const {page, per_page,order_by,sort_by } = this.state;
const url = `http://myapp.com/api/mobile/credit?page=${page}&api_token=${this.props.token}&per_page=${per_page}&order_by=${order_by}&sort_by=${sort_by}`;
console.log("the url",url);
this.setState({ loading: true });
setTimeout(()=>{
fetch(url)
.then(res => res.json())
.then(res => {
console.log("the page is =",this.getParameterByName('page',res.next_page_url));
this.setState({
page:this.getParameterByName('page',res.next_page_url),
data: this.state.page === 1 ? res.data : [...this.state.data,...res.data],
error: res.error || null,
loading: false,
refreshing: false,
last_page: res.last_page
});
})
.catch(error => {
this.setState({ error, loading: false });
});
},1500);
};
handleRefresh = () => {
if( this.state.page) {
if (this.state.page <= this.state.last_page) {
this.setState(
{
refreshing: true,
page: this.state.page
},
() => {
this.makeRemoteRequest();
}
);
}
}
};
getParameterByName = (name,url) =>{
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
let regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return parseInt(decodeURIComponent(results[2].replace(/\+/g, " ")), 10);
};
handleLoadMore = () => {
if( this.state.page){
if( this.state.page <= this.state.last_page ){
this.setState(
{
page: this.state.page
},
() => {
this.makeRemoteRequest();
}
);
}else{
console.log("cannot handle more",this.state.page)
}
}else{
console.log("page is null");
}
};
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "86%",
backgroundColor: "#CED0CE",
marginLeft: "14%"
}}
/>
);
};
renderHeader = () => {
return (
<View >
<Text h1
style={{
color: 'blue',
fontWeight: 'bold',
textAlign: 'center',
fontSize: 30,
backgroundColor: "#CED0CE",
}}
>{ numeral(this.props.thetotalcredit).format("#,##0.00") }</Text>
</View>
);
};
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
borderColor: "#CED0CE"
}}
>
<ActivityIndicator animating size="large" />
</View>
);
};
render() {
return (
<FlatList
data={this.state.data}
keyExtractor = {(item, index) => index.toString()}
renderItem={({ item }) => (
<ListItem
title= { numeral(item.amountcredit).format("#,##0.00") }
subtitle= { moment(item.creditdate).format("MMM DD, YYYY") }
containerStyle={{ borderBottomWidth: 0 }}
/>
)}
extraData={this.state.data}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
refreshing={this.state.refreshing}
onRefresh={this.handleRefresh}
onEndReached={this.handleLoadMore}
onEndReachedThreshold={0.5}
stickyHeaderIndices={[0]}
/>
);
}
}
const mapStateToProps = (state) => {
return {
username: state.auth.username,
token:state.auth.token,
thetotalcredit:state.auth.total_credit
};
};
export default connect(mapStateToProps)(Screen1);