How to set dynamic data in react? - reactjs

I have got series of data that contains some objects in one array(json file) and it will be shown by react.
const Library = [
{
name: "Star Wars"
},
{
name: "Harry Potter"
},
{
name: "Lord of the Rings"
},
{
name: "Star Trek"
},
{
name: "The Fault in Our Stars"
},
{
name: "Number the Stars"
},
{
name: "Blue"
},
{
name: "Act Da Fool"
},
{
name: "The Gilded Cage"
},
{
name:
"To Get to Heaven First You Have to Die (Bihisht faqat baroi murdagon)"
},
{
name: "Lebanon"
},
{
name: "Tenderness"
},
{
name: "It"
},
{
name: "Locked Out (Enfermés dehors)"
},
{
name: "Waterloo Bridge"
},
{
name: "Set It Off"
},
{
name: "Nil By Mouth"
},
{
name: "Monte Carlo"
},
{
name: "Treasure of the Four Crowns"
},
{
name: "Donnie Darko"
},
{
name: "Cry-Baby"
},
{
name: "Juan of the Dead (Juan de los Muertos)"
},
{
name: "Constant Nymph, The"
}
];
// Main App Component
class App extends React.Component {
constructor(props){
super();
this.state = {
library: null,
perPage: 1,
currentPage: 1,
maxPage: null,
filter: ""
};
}
componentDidMount() {
this.reorganiseLibrary();
}
// Calculates the library
reorganiseLibrary = () => {
const { filter, perPage } = this.state;
let library = Library;
console.log(library)
if (filter !== "") {
library = library.filter(item =>
item.hotelinfo.hotelsearch.realname.toLowerCase().includes(filter)
);
}
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
});
};
// Previous Page
previousPage = () =>
this.setState(prevState => ({
currentPage: prevState.currentPage - 1
}));
// Next Page
nextPage = () =>
this.setState(prevState => ({
currentPage: prevState.currentPage + 1
}));
// handle filter
handleFilter = evt =>
this.setState(
{
filter: evt.target.value.toLowerCase()
},
() => {
this.reorganiseLibrary();
}
);
// handle per page
handlePerPage = (evt) =>
this.setState({
perPage: evt.target.value
}, () => this.reorganiseLibrary());
// handle render of library
renderLibrary = () => {
const { library, currentPage } = this.state;
if (!library || (library && library.length === 0)) {
return <div>No results</div>;
}
return library[currentPage - 1].map(item => (
<div key={item.hotelinfo.hotelsearch.realname}>{item.hotelinfo.hotelsearch.realname}</div>
));
};
render() {
const { library, currentPage, perPage, maxPage } = this.state;
return (
<div className="library">
<h1>Library</h1>
<div className="d-flex">
<div className="flex-fill">
<label className="library__filter-label">Filter</label>
<input value={this.state.filter} onChange={this.handleFilter} />
</div>
<div className="flex-fill text-right">
<label className="library__per-page-label">Per page</label>
<input placeholder="per page" value={this.state.perPage} onChange={this.handlePerPage} />
</div>
</div>
<div className="library__book-shelf">
{this.renderLibrary()}
</div>
<div className="d-flex">
<div className="flex-fill">
{currentPage !== 1 && (
<button onClick={this.previousPage}>Previous</button>
)}
</div>
<div className="flex-fill text-right">
{(currentPage < maxPage) && (
<button onClick={this.nextPage}>Next</button>
)}
</div>
</div>
<div className="library__page-info text-right">
{this.state.currentPage} of {this.state.maxPage}
</div>
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
The data of Library is going to be dynamic and the data will be sent from another page to this page by ajax request but as you can see data is set statically. How to set data of Library dynamiclly.
I try below code biy there is this error :
ReferenceError: Library is not defined
Component {
constructor(props){
super();
this.state = {
Library:[],
library: null,
.....
};
$.ajax({
url:"/json.bc",
type:"post",
data:{
cityid:"1182348",
rooms:JSON.stringify({"rooms":[{"adultcount":"1","childcountandage":"0"}]}),
},
success:(result)=>{
this.setState({Library: eval(result)}); } }) }
. . .
}
Edited code :
class App extends React.Component {
constructor(props){
super();
this.state = {
Library:[],
library: null,
perPage: 1,
currentPage: 1,
maxPage: null,
filter: "",
};
}
componentDidMount() {
$.ajax({
url:"/test1.bc",
type:"post",
data:{
cityid:"1182348",
rooms:JSON.stringify({"rooms":[{"adultcount":"1","childcountandage":"0"}]}),
},
success:(result)=>{
this.setState({Library: eval(result)}); }
})}
componentDidMount() {
this.reorganiseLibrary();
}
// Calculates the library
reorganiseLibrary = () => {
const { filter, perPage } = this.state;
let library = Library;
console.log(library)
if (filter !== "") {
library = library.filter(item =>
item.hotelinfo.hotelsearch.realname.toLowerCase().includes(filter)
);
}
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
});
};
// Previous Page
previousPage = () =>
this.setState(prevState => ({
currentPage: prevState.currentPage - 1
}));
// Next Page
nextPage = () =>
this.setState(prevState => ({
currentPage: prevState.currentPage + 1
}));
// handle filter
handleFilter = evt =>
this.setState(
{
filter: evt.target.value.toLowerCase()
},
() => {
this.reorganiseLibrary();
}
);
// handle per page
handlePerPage = (evt) =>
this.setState({
perPage: evt.target.value
}, () => this.reorganiseLibrary());
// handle render of library
renderLibrary = () => {
const { library, currentPage } = this.state;
if (!library || (library && library.length === 0)) {
return <div>No results</div>;
}
return library[currentPage - 1].map(item => (
<div key={item.hotelinfo.hotelsearch.realname}>{item.hotelinfo.hotelsearch.realname}</div>
));
};
render() {
const { library, currentPage, perPage, maxPage } = this.state;
return (
<div className="library">
<h1>Library</h1>
<div className="d-flex">
<div className="flex-fill">
<label className="library__filter-label">Filter</label>
<input value={this.state.filter} onChange={this.handleFilter} />
</div>
<div className="flex-fill text-right">
<label className="library__per-page-label">Per page</label>
<input placeholder="per page" value={this.state.perPage} onChange={this.handlePerPage} />
</div>
</div>
<div className="library__book-shelf">
{this.renderLibrary()}
</div>
<div className="d-flex">
<div className="flex-fill">
{currentPage !== 1 && (
<button onClick={this.previousPage}>Previous</button>
)}
</div>
<div className="flex-fill text-right">
{(currentPage < maxPage) && (
<button onClick={this.nextPage}>Next</button>
)}
</div>
</div>
<div className="library__page-info text-right">
{this.state.currentPage} of {this.state.maxPage}
</div>
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('root'));

You can try this:
getData = (callback) => {
$.ajax({
url:"/json.bc",
type:"post",
data:{
cityid:"1182348",
rooms:JSON.stringify({"rooms":[{"adultcount":"1","childcountandage":"0"}]}),
},
success:(result)=>{
callback(eval(result))
}
. . .
}
}
setData = () => {
this.getData(data => { this.setState({ Library: data }) } )
}

Try calling the ajax call in componentDidMount() set state.
componentDidMount() {
$.ajax({
url:"/json.bc",
type:"post",
data:{
cityid:"1182348",
rooms:JSON.stringify({"rooms":[{"adultcount":"1","childcountandage":"0"}]}),
},
success:(result)=>{
this.setState({Library: eval(result)}); } }) }
. . .
}
}

Related

How do I search data with pagination in React?

class Employee extends Component {
constructor() {
super();
this.state = {
// employees: employees,
employees: [],
searchfield: "",
currentPage: 1,
resultsPerPage: 50,
holder: [],
filteredEmployees: [],
value: "",
};
}
componentDidMount = async () => {
axios.get(`http://localhost:5000/`).then((res) => {
const employees = res.data;
this.setState({
employees: employees.recordsets[0],
holder: employees.recordsets[0],
});
});
};
onSearchChange = (event) => {
let { value } = event.target;
this.setState({ value }, () => {
var updatedList = this.state.holder;
updatedList = updatedList.filter((employee) => {
const fullName = employee.empFirstNm + " " + employee.empLastNm;
return (
fullName.toLowerCase().search(this.state.value.toLowerCase()) !== -1
);
});
this.setState({ employees: updatedList });
});
};
//change page
onPaginate = (pageNumber) => {
this.setState({ currentPage: pageNumber });
};
render() {
const { employees, searchfield, currentPage, resultsPerPage } = this.state;
const { onRouteChange } = this.props;
//Get current employees
const indexOfLastEmployee = currentPage * resultsPerPage;
const indexOfFirstEmployee = indexOfLastEmployee - resultsPerPage;
console.log("indexOfFirstEmployee: ", indexOfFirstEmployee);
console.log("indexOfLastEmployee: ", indexOfLastEmployee);
const filteredEmployees = employees.slice(
indexOfFirstEmployee,
indexOfLastEmployee
);
return !employees.length ? (
<div className="tc">
<h1>Loading</h1>
<Spinner animation="border" variant="danger" />
</div>
) : (
<FadeIn>
<div className="tc">
<div
className="
d-flex
justify-content-between
flex-wrap
flex-md-nowrap
align-items-center
pt-3
pb-2
mb-3
border-bottom"
>
<h1 className="display-2">Employees</h1>
<div
className="tr"
style={{
margin: "15px 0",
}}
>
<NewEmployee employees={employees} />
<SearchBox
searchChange={this.onSearchChange}
value={this.state.value}
/>
</div>
</div>
<Scroll>
<CardList
employees={filteredEmployees}
onDelete={this.handleDelete}
onRouteChange={onRouteChange}
/>
<Table
employees={filteredEmployees}
onRouteChange={onRouteChange}
/>
<Pagination
resultsPerPage={resultsPerPage}
totalResults={employees.length}
onPaginate={this.onPaginate}
/>
</Scroll>
</div>
</FadeIn>
);
}
}
I have tried implementing it with conditions of whether the results
is greater than or equal to the results on a page but it did not
work since it doesnt cover every single case based on the result.
I am getting the search to work but when my current page is anything besides 1 is when the search doesn't work.
Any idea how I can get the filtering to work regardless of what page I
am on?
Figured this out. I just needed to set currentPage to 1 at the end of my search:
onSearchChange = (event) => {
let { value } = event.target;
this.setState({ value }, () => {
//running this after setting the value in state because of async
var updatedList = this.state.holder;
updatedList = updatedList.filter((employee) => {
const fullName = employee.empFirstNm + " " + employee.empLastNm;
return (
fullName.toLowerCase().search(this.state.value.toLowerCase()) !== -1
);
});
this.setState({ employees: updatedList });
this.setState({ currentPage: 1 });
});

componentWillReceiveProps render multiple times

I am getting datas from my database using three different functions, but as I've seen componentWillReceiveProps is rerendering for three times in this case, which cause duplicating my elements in the frontend. How can I render it just once, or only object's props really change. Till now, my follows[] array objects are duplicating
class UserDashboard extends React.Component {
state = {
uid: this.props.userDetails.uid,
page: 1,
redirect: false,
target: 15,
selectedRole: 4,
selectedSourceRole: 1,
quote_nr: '',
source_id: '',
status_id: '',
cost: '',
rebate: '',
pageLoading: false,
date: '2222-01-02',
therapists:[],
globalTargets:[],
follows:[],
utc: new Date().toISOString().slice(0, 19).replace('T', ' '),
}
topProfilesUrl = 'therapists/top/profiles';
getGlobalTargets = 'owner/targets';
followActivities = 'user/follow/activities';
componentDidMount = () => {
const { getActivities,getFollowActivities,getTarget } = this;
getActivities();
getFollowActivities();
getTarget();
window.scrollTo(0, 0);
}
UNSAFE_componentWillReceiveProps = (newProps) => {
let apiDat = newProps.apiDat;
let apiData = newProps.apiData;
if (apiData.activities && apiData.activities.success ) {
let therapists = apiData.activities.therapists;
let hasMore = true;
console.log("unu")
if (therapists.length < 10) {
hasMore = false;
}
this.setState(() => ({
therapists: this.state.therapists.concat(therapists),
hasMore: hasMore,
pageLoading: false
}))
}
if (apiDat.targets && apiDat.targets.success) {
console.log("doi")
let globalTargets = apiDat.targets.globals;
let hasMore = true;
if (globalTargets.length < 10) {
hasMore = false;
}
this.setState(() => ({
globalTargets: this.state.globalTargets.concat(globalTargets),
}))
}
if (apiData.followActivities && apiData.followActivities.success) {
console.log("trei")
let follows = apiData.followActivities.follows;
let hasMore = true;
if (follows.length < 10) {
hasMore = false;
}
this.setState(() => ({
follows: this.state.follows.concat(follows),
}))
}
}
getTarget = () => {
this.setState({pageLoading: true}, () => { this.loadTargets() })
}
loadTargets = () => {
console.log("load")
this.props.actions.reqGetGlobalTargets({
body: {},
headers: null,
resource: `${this.getGlobalTargets}?page=${this.state.page}`
})
}
getFollowActivities= () => {
this.setState({pageLoading: true}, () => { this.loadFollowActivities() })
}
loadFollowActivities = () => {
console.log("load")
this.props.actions.reqGetFollowActivities({
body: {},
headers: null,
resource: `${this.followActivities}?page=${this.state.page}`
})
}
renderLeads = () => {
return (
this.state.globalTargets.slice(0,1).map( (t, idx) => (
t.daily_leads
))
)
}
renderSales = () => {
return (
this.state.globalTargets.slice(0,1).map( (t, idx) => (
t.daily_sales
))
)
}
renderRatio = () => {
return (
this.state.globalTargets.slice(0,1).map( (t, idx) => (
t.close_ratio
))
)
}
getActivities = () => {
this.setState({pageLoading: true}, () => { this.loadActivities() })
}
loadActivities = () => {
this.props.actions.reqGetTherapistsTopProfiles({
body: {},
headers: null,
resource: `${this.topProfilesUrl}?page=${this.state.page}`
})
}
renderActivities = () => {
const items = this.state.therapists.map( (t, idx) => (
<tr key={t.id} className="activity-display-table">
<td>Quote Nr.: {t.quote_nr}</td>
<td>Source: {t.source_id}</td>
<td>Status: {t.status_id}</td>
<td>Cost: ${t.cost}</td>
<td>Rebate: ${t.rebate}</td>
<td>Date: {t.date.slice(0,10).replace(/-/g,'-')}</td>
</tr>
))
return (
<div ref={0} className="therapist-list">
<h2>Your Past Entries: </h2>
{ items }
</div>
)
}
renderFollowActivities = () => {
const items = this.state.follows.map( (t, idx) => (
<tr key={t.id} className="activity-display-table">
<td>Quote Nr.: {t.quote_nr}</td>
<td>Source: {t.source_id}</td>
<td>Status: {t.status_id}</td>
<td>Cost: ${t.cost}</td>
<td>Rebate: ${t.rebate}</td>
<td>Date: {t.date.slice(0,10).replace(/-/g,'-')}</td>
</tr>
))
return (
<div ref={0} className="therapist-list">
{ items }
</div>
)
}
submitUrl = 'registerActivities';
handleChange = (eve) => {
let inputName = eve.target.name,
value = eve.target.value;
this.setState(() => {
return {[inputName]: value}
})
}
handleSubmit = () => {
this.setState(() => {
const acBody = {
quote_nr: this.state.quote_nr,
cost: this.state.cost,
source_id: this.state.selectedSourceRole,
status_id: this.state.selectedRole,
date: this.state.utc,
rebate: this.state.rebate,
user_id:this.state.uid,
}
this.props.actions.reqActionsUsers(acBody, this.submitUrl);
})
}
handleStatusChange = (event) => {
let statusId = event.target.value;
this.setState(() => ({
selectedRole: statusId
}))
}
handleSourceChange = (ev) => {
let statusId = ev.target.value;
this.setState(() => ({
selectedSourceRole: statusId
}))
}
render () {
console.log(this.state.follows);
return (
<MainWrapper>
<div id="user-dashboard">
<HeaderUser logoutRedirect="/signin"/>
<div className="page-background">
<SidebarUser page="dashboard"/>
{/* Page Content */}
<div className="inner-content">
<div className="top-row">
<h1>Salesperson Dashboard</h1>
</div>
<div className="second-row">
</div>
<div className="activity-table">
<table className="a">
<tr>
<th>Today's Targets ({this.state.utc.slice(0,10).replace(/-/g,'-')})</th>
<th>Weekly Targets</th>
<th>Bonus So Far This Week</th>
</tr>
<tr>
<td>0/{this.renderLeads()} Leads Handled</td>
<td>0/{this.renderLeads()*5} Leads Handled</td>
<td>$0 From Leads</td>
</tr>
<tr>
<td>0/{this.renderSales()} Sales</td>
<td>0/{this.renderSales()*5} Sales</td>
<td>$0 From Sales</td>
</tr>
<tr>
<td>0/{this.renderRatio()} Close Ratio</td>
<td>0/{this.renderRatio()*5} Close Ratio</td>
<td>$0 From Profit Share</td>
</tr>
</table>
</div>
<div>
<h2>Leads Due For A Followup</h2>
{ this.renderFollowActivities() }
</div>
<h2 className="activity">Add Activity</h2>
<div className="activity-menu">
<input type="text"
placeholder="Quote Number"
name="quote_nr"
onChange={this.handleChange}
/>
<select onChange={this.handleSourceChange}>
<option value="1">Phone</option>
<option value="2">Email</option>
<option value="3">Live Chat</option>
</select>
<select onChange={this.handleStatusChange}>
<option value="4">Lead</option>
<option value="5">Sold</option>
</select>
<input type="text"
placeholder="Cost"
name="cost"
onChange={this.handleChange}
/>
<input type="text"
placeholder={this.state.cost/20||("Recom. Rebate" + " $")}
name="recRebate"
readOnly
/>
<input type="text"
placeholder={this.state.cost/10||("Max Possible Rebate" + " $")}
name="maxRebate"
readOnly
/>
<input type="text"
placeholder="Final Rebate $"
name="rebate"
onChange={this.handleChange}
/>
</div>
<ButtonRoundGradient className="activity_button" text="Add Activity" onClick={this.handleSubmit}/>
{ this.renderActivities() }
</div>
</div>
</div>
</MainWrapper>
)
}
}
const mapStateToProps = state => ({
apiData: state.activities,
apiDat: state.targets,
userDetails: state.userDetails
})
function mapDispatchToProps(dispatch) {
return {
actions: {
reqGetGlobalTargets: bindActionCreators(reqGetGlobalTargets, dispatch),
reqGetFollowActivities: bindActionCreators(reqGetFollowActivities, dispatch),
reqGetTherapistsTopProfiles: bindActionCreators(reqGetTherapistsTopProfiles, dispatch),
reqFetchUserDetails: bindActionCreators(reqFetchUserDetails, dispatch),
reqActionsUsers: bindActionCreators(reqActionsUsers, dispatch),
}
};
}
export default connect(mapStateToProps, mapDispatchToProps)(UserDashboard)
ComponentWillRecieveProps would be called every time your state changes or your state changes, so if you want to stop duplicating, you should do this :
componentWillReceiveProps(nextProps, nextContext) {
if (JSON.stringify(nextProps.someProps.items) !== JSON.stringift(this.state.items)){
// do something
}
}
basically you should check if props and state of your component should react to the situation, then really render your application.
hope that helps

DefaultValue in input by type=range

I have an Input by type=range that the value of min , max and defaultvalue would be set by {this.renderMinTotal()} and {this.renderMaxTotal()} and as you can see the value of defaultvalue is the output of {this.renderMaxTotal()} but the thumb of input looks that the value of defaultvalue is {this.renderMinTotal()} while the value of defaultvalue is {this.renderMaxTotal()} and in inspector the values of min , max and defaultvalue are correct.
The output of input in inspector:
<input type="range" min="17386000" max="178124000" step="1000" class="multirange" value="178124000">
It must be like this:
=============[]
while it looks like this:
[]=============
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
library: null,
perPage: 20,
currentPage: 1,
maxPage: null
};
}
componentDidMount() {
fetch("/json.bc", {
method: "get"
})
.then(response => response.text())
.then(text => {
let Maindata = JSON.parse(text.replace(/\'/g, '"'));
this.setState(
state => ({
...state,
data: Maindata
}),
() => {
this.reorganiseLibrary();
}
);
})
.catch(error => console.error(error));
}
reorganiseLibrary = () => {
const { perPage, data } = this.state;
let library = data;
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
});
};
// Previous Page
previousPage = event => {
this.setState({
currentPage: this.state.currentPage - 1
});
};
// Next Page
nextPage = event => {
this.setState({
currentPage: this.state.currentPage + 1
});
};
// handle per page
handlePerPage = evt =>
this.setState(
{
perPage: evt.target.value
},
() => this.reorganiseLibrary()
);
// handle render of library
renderLibrary = () => {
const { library, currentPage } = this.state;
if (!library || (library && library.length === 0)) {
return <div className="nodata">NoResult</div>;
}
return library[currentPage - 1]
.sort((a, b) => a.total - b.total)
.map((item, i) => (
<div className="item">
<span>{item._id.value} </span>
</div>
));
};
renderMinTotal = () => {
const { library } = this.state;
if (!library || (library && library.length === 0)) {
return "";
}
return library.reduce((acc, lib) => {
const libMin = Math.min(...lib.map(item => item.totalCom));
return acc === undefined ? libMin : libMin < acc ? libMin : acc;
}, undefined);
};
renderMaxTotal = () => {
const { library } = this.state;
if (!library || (library && library.length === 0)) {
return "";
}
return library.reduce((acc, lib) => {
const libMax = Math.max(...lib.map(item => item.totalCom));
return libMax > acc ? libMax : acc;
}, 0);
};
render() {
const { library, currentPage, perPage, maxPage } = this.state;
return (
<div>
<div>
<input
type="range"
min={this.renderMinTotal()}
max={this.renderMaxTotal()}
defaultValue={this.renderMaxTotal()}
step="1000"
className="multirange"
/>
</div>
{this.renderLibrary()}
<ul id="page-numbers">
<li className="nexprevPage">
{currentPage !== 1 && (
<button onClick={this.previousPage}>
<span className="fa-backward" />
</button>
)}
</li>
<li className="controlsPage active">{this.state.currentPage}</li>
<li className="restControls">...</li>
<li className="controlsPage">{this.state.maxPage}</li>
<li className="nexprevPage">
{currentPage < maxPage && (
<button onClick={this.nextPage}>
<span className="fa-forward" />
</button>
)}
</li>
</ul>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('Result'))
Edited Code:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
library: null,
};
}
componentDidMount() {
fetch("/json.bc", {
method: "get"
})
.then(response => response.text())
.then(text => {
let Maindata = JSON.parse(text.replace(/\'/g, '"'));
this.setState(
state => ({
...state,
data: Maindata
}),
() => {
this.reorganiseLibrary();
}
);
})
.catch(error => console.error(error));
}
reorganiseLibrary = () => {
const { data } = this.state;
let library = data;
library = _.chunk(library);
this.setState({
library,
});
};
// handle per page
handlePerPage = evt =>
this.setState(
{
perPage: evt.target.value
},
() => this.reorganiseLibrary()
);
renderMinTotal = () => {
const { library } = this.state;
if (!library || (library && library.length === 0)) {
return "";
}
return library.reduce((acc, lib) => {
const libMin = Math.min(...lib.map(item => item.totalCom));
return acc === undefined ? libMin : libMin < acc ? libMin : acc;
}, undefined);
};
renderMaxTotal = () => {
const { library } = this.state;
if (!library || (library && library.length === 0)) {
return "";
}
return library.reduce((acc, lib) => {
const libMax = Math.max(...lib.map(item => item.totalCom));
return libMax > acc ? libMax : acc;
}, 0);
};
render() {
const { library } = this.state;
return (
<div>
<div>
<input
type="range"
min={this.renderMinTotal()}
max={this.renderMaxTotal()}
defaultValue={this.renderMaxTotal()}
step="1000"
className="multirange"
/>
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('Result'))

Reactjs: How to properly fetch each users record from database on pop button click using Reactjs

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.

Set the result of ajax in react

Why the result of ajax request doesn't set in Library which is [] by default.When the data of Library is set statically there would not be problem :
Library:[{'id': '5c0b6cd9e1382352759fbc25', 'hotelinfo': {'name': 'Korston Hotel', 'hotelsearch': {'realname': 'Korston Hotel Moscow', 'hotelid': 1011702.0, 'hotelimage': 'htl207110100001', 'countryid': 1002035.0, 'ecountryname': 'Russia', 'countryname': '', 'cityid': 1182348.0, 'ecityname': 'Moscow', 'cityname': '', 'star': 4.0, 'services': 'H.B', 'desc': ' ', 'enable': '1', 'delete': '0'}, 'information': {'viewname': ''}, 'validatedate': {'fdate': '1397-12-01', 'tdate': '1397-12-29', 'tdateid': 10592.0, 'fdateid': 10564.0}}, 'families': [{'availablerooms': [{'info': {'room': 'Single', 'cost': 2400.0, 'availability': 'onrequest', 'withbed': 0.0, 'withoutbed': 0.0, 'adults': 1.0, 'infant': 0.0, 'roomid': '1011702_483587', 'double': '0'}}], 'optionId': '1011702_483587###5c0b6cd9e1382352759fbc25', 'totalPrice': 2400.0, 'services': 'H.B', .....]
but Library is going to be dynamic and the data will be sent from another page to this page by ajax request.
What should I do to set the result of ajax request in Library.
class App extends React.Component {
constructor(props) {
super();
this.state = {
Library: [],
library: null,
perPage: 1,
currentPage: 1,
maxPage: null,
filter: ""
};
$.ajax({
url: "/json.bc",
type: "post",
data: {
cityid: "1182348",
rooms: JSON.stringify({ "rooms": [{ "adultcount": "1", "childcountandage": "0" }] }),
},
success: (result) => {
this.setState({ Library: eval(result) });
}
})
}
componentDidMount() {
this.reorganiseLibrary();
}
// Calculates the library
reorganiseLibrary = () => {
const { filter, perPage, Library } = this.state;
let library = Library;
console.log(Library) //There is no result here//
if (filter !== "") {
library = library.filter(item =>
item.hotelinfo.hotelsearch.realname.toLowerCase().includes(filter)
);
}
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
});
};
// Previous Page
previousPage = () =>
this.setState(prevState => ({
currentPage: prevState.currentPage - 1
}));
// Next Page
nextPage = () =>
this.setState(prevState => ({
currentPage: prevState.currentPage + 1
}));
// handle filter
handleFilter = evt =>
this.setState(
{
filter: evt.target.value.toLowerCase()
},
() => {
this.reorganiseLibrary();
}
);
// handle per page
handlePerPage = (evt) =>
this.setState({
perPage: evt.target.value
}, () => this.reorganiseLibrary());
// handle render of library
renderLibrary = () => {
const { library, currentPage } = this.state;
if (!library || (library && library.length === 0)) {
return <div>No results</div>;
}
return library[currentPage - 1].map(item => (
<div key={item.hotelinfo.hotelsearch.realname}>{item.hotelinfo.hotelsearch.realname}</div>
));
};
render() {
const { library, currentPage, perPage, maxPage } = this.state;
return (
<div className="library">
<h1>Library</h1>
<div className="d-flex">
<div className="flex-fill">
<label className="library__filter-label">Filter</label>
<input value={this.state.filter} onChange={this.handleFilter} />
</div>
<div className="flex-fill text-right">
<label className="library__per-page-label">Per page</label>
<input placeholder="per page" value={this.state.perPage} onChange={this.handlePerPage} />
</div>
</div>
<div className="library__book-shelf">
{this.renderLibrary()}
</div>
<div className="d-flex">
<div className="flex-fill">
{currentPage !== 1 && (
<button onClick={this.previousPage}>Previous</button>
)}
</div>
<div className="flex-fill text-right">
{(currentPage < maxPage) && (
<button onClick={this.nextPage}>Next</button>
)}
</div>
</div>
<div className="library__page-info text-right">
{this.state.currentPage} of {this.state.maxPage}
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
First off, unless you really, really have to, try to avoid using jQuery in React. It's just going to lead to a massive headache.
You need to move that Ajax request out of the constructor and into your componentDidMount method. For example:
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
Library: [],
}
}
componentDidMount() {
fetch('/json.cs')
.then(response => response.json())
.then(data => {
this.setState(state => ({
...state,
Library: data
}), () => {
this.reorganiseLibrary()
})
}
}
}
You have to call Ajax to load remote content inside componentDidMount
componentDidMount() {
// call your ajax and set state
}
Moreover, you need to remove this.reorganiseLibrary(); inside componentDidMount or call it along with this.setState({ Library: eval(result) }); after calling ajax to improve performance.

Resources