React Redux showing data in table from API - reactjs

Currently, my application showing initialState data in the table and those data are hardcoded. I want to show my API fetched data in the table.
this is my postReducer.js file:
var initialState = {
employees: [
{ id: 1, name: 'jhon', age: '23'},
{ id: 2, name: 'doe', age: '24'}
]
};
var postReducer = (state = initialState, action) => {
switch (action.type) {
case 'ADD_POST':
return {
...state,
employees: [...state.employees, action.data],
};
case 'EDIT_POST':
return {
...state,
employees: state.employees.map(emp => emp.id === action.data.id ? action.data : emp)
};
case 'DELETE_POST':
console.log(action.data.id)
return {
...state,
employees: [...state.employees.filter((post)=>post.id !== action.data.id)],
};
default:
return state;
}
};
export default postReducer;
and this is my table.js file
import React, {Fragment} from "react";
import { connect } from "react-redux";
class Table extends React.Component {
onEdit = (item) => { //Use arrow function to bind `this`
this.props.selectedData(item);
}
onDelete = (id) => {
const data = {
id,
}
this.props.dispatch({ type: 'DELETE_POST', data });
}
render() {
return (
<Fragment>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Age</th>
<th scope="col">Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{this.props.employees.map((item, index) => (
<tr key={index}>
<td>{item.name}</td>
<td>{item.age}</td>
<td>
<button
type="button"
onClick={() => this.onEdit(item)}>EDIT
</button>
<button
onClick={ () => this.onDelete(item.id) }>DELETE
</button>
</td>
</tr>
))}
</tbody>
</Fragment>
);
}
}
const mapStateToProps = (state) => ({ employees: state.employees });
export default connect(mapStateToProps)(Table);
and this my form.js file
import React, { Fragment } from "react"
import { connect } from 'react-redux'
const axios = require('axios');
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
id: this.props.selectedData.id,
name: this.props.selectedData.name,
age: this.props.selectedData.age,
};
this.onHandleChange = this.onHandleChange.bind(this);
this.submit = this.submit.bind(this);
}
submit(event) {
const data = {
name: this.state.name,
age: this.state.age,
email: this.state.email
};
if (this.props.isEdit) {
data.id = this.props.selectedData.id;
console.log('edit', data);
this.props.dispatch({ type: 'EDIT_POST', data })
} else {
// generate id here for new emplyoee
this.props.dispatch({ type: 'ADD_POST', data })
}
}
onHandleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
componentDidUpdate(prevProps) {
if (prevProps.selectedData.age !== this.props.selectedData.age) { //Check on email, because email is unique
this.setState({ name: this.props.selectedData.name, age: this.props.selectedData.age })
}
}
render() {
return (
<form>
<div className="form-group">
<input onChange={(event) => this.onHandleChange(event)} value={this.state.name} name="name" type="text" />
</div>
<div className="form-group">
<input onChange={(event) => this.onHandleChange(event)} value={this.state.age} name="age" type="number" />
</div>
<button onClick={(event) => this.submit(event)} type="button">
{this.props.isEdit ? 'Update' : 'SAVE'}
</button>
</form>
);
}
}
export default connect(null)(Form);
I think i need to work on table.js file to implement, i tried with componentDidmount but i failed to implement is.
I am using Axios for http request
this is the request snippet with api:
axios.get('http://127.0.0.1:8000/api/v1/employee/')
.then(function (response) {
// handle success
})
.catch(function (error) {
// handle error
})
.finally(function () {
});
I am not getting how to successfully implement this like when i visit the page, i should see the table with data that come from api endpoint.
Can anyone help me regarding this?

In your Table component, you can make use of componentDidMount for your API call,
componentDidMount(){
axios.get('http://127.0.0.1:8000/api/v1/employee/')
.then((response) => { //Use arrow function to auto bind `this`
// handle success
this.props.dispatch({ type: 'ADD_POST', response.data }) //considering response.data is the correct array
})
.catch(function (error) {
// handle error
})
.finally(function () {
});
}

Related

How to change let value onClick in React

My default value is null (let activestatus = "";), but I want it to change on click to be:
let activestatus = "?IsActive=0";
I am getting value on click (as seen in console), but the value is not passed in "let activestatus".
class App extends Component {
state = {
reservations: [],
};
componentWillMount() {
let activestatus = "";
axios
.get("https://localhost:44307/api/GetReservations/" + `${activestatus}`)
.then((response) => {
this.setState({
reservations: response.data,
});
});
}
showActive = (e) => {
e.preventDefault();
console.log(e.target.value);
this.activestatus = e.target.value;
};
render() {
let reservations = this.state.reservations.map((reservation) => {
return (
<tr>
<td>{reservation.Id}</td>
</tr>
);
});
return (
<div className="App container">
<Button
class="activity-button"
value={"?IsActive=0"}
id="active"
onClick={this.showActive}
>
Can you try to have activeStatus as part of your state? Also if you want to refresh the data from the api based on this field, then should probably use componentDidUpdate that runs on state changes.
class App extends Component {
state = {
reservations: [],
activestatus: ""
};
componentWillMount() {
axios
.get("https://localhost:44307/api/GetReservations/" + `${activestatus}`)
.then((response) => {
this.setState({
reservations: response.data,
});
});
}
showActive = (e) => {
e.preventDefault();
console.log(e.target.value);
this.setState({ activestatus: e.target.value });
};
render() {
let reservations = this.state.reservations.map((reservation) => {
return (
<tr>
<td>{reservation.Id}</td>
</tr>
);
});
return (
<div className="App container">
<Button
class="activity-button"
value={"?IsActive=0"}
id="active"
onClick={this.showActive}
>`
Thanks guys, both were helpful.
Solution:
class App extends Component {
state = {
reservations: [],
activestatus: "",
};
componentDidUpdate() {
axios
.get(
"https://localhost:44307/api/GetReservations/" +
`${this.state.activestatus}`
)
.then((response) => {
this.setState({
reservations: response.data,
});
});
}
}
showActive = (e) => {
e.preventDefault();
console.log(e.target.value);
this.setState({ activestatus: e.target.value });
};
render() {
let reservations = this.state.reservations.map((reservation) => {
return (
<tr>
<td>{reservation.Id}</td>
</tr>
);
});
return (
<div className="App container">
<Button
class="activity-button"
value={"?IsActive=0"}
id="active"
onClick={this.showActive}
>`

sending input value to backend using react & axios

I am basically trying to allow myself to edit a field on a page, and then when I am done editing it, just hit the submit button, and it will send it to the backend, where it will update my mongodb collection. I have this (this is my whole page -- so there's no confusion)
import { render } from "react-dom";
import React, { Component } from "react";
import axios from "axios";
import "../styles/TourPage.css";
class TourPage extends Component {
constructor(props) {
super(props);
this.state = {
myData: [],
isLoading: true
};
}
componentDidMount() {
axios
.get("/getResults")
.then((res) => {
this.setState({
myData: res.data
});
})
.catch((error) => {
// Handle the errors here
console.log(error);
})
.finally(() => {
this.setState({
isLoading: false
});
});
}
deleteById = (id) => {
console.log(id)
axios
.post(`/deleteDoc`, {id: id} )
.then(() => {
console.log(id, " worked")
window.location = "/tour"
})
.catch((error) => {
// Handle the errors here
console.log(error);
})
}
editById = (id, location, Services, cnum) => {
console.log(id, location, Services, cnum)
axios
.post(`/editDoc`, {id: id, location: location, Services: Services, cnum: cnum} )
.then(() => {
console.log(id, " worked")
window.location = "/tour"
})
.catch((error) => {
// Handle the errors here
console.log(error);
})
}
render() {
// You can handle the loader part here with isLoading flag. In this case No data found will be shown initially and then the actual data
let { myData, isLoading } = this.state;
return (
<table id="customers">
<tr>
<th>siteLocation</th>
<th>Services</th>
<th>cnum</th>
</tr>
{myData.length > 0
? myData.map(({ location, Services, cnum, _id }, index) => (
<tr key={index}>
<td><input type="text" placeholder={location} /> </td>
<td>{Services}</td>
<td>{cnum}</td>
<button
onClick={() => this.deleteById(_id)}
disabled={isLoading}
>
Delete
</button>
<button
onClick={() => this.editById(_id, location, Services, cnum)}
disabled={isLoading}
>
Submit Edit
</button>
</tr>
))
: "No Data Found"}
</table>
);
}
}
export default TourPage;
as you an see, in the section where I am making the request to /editDoc, I am trying to pass the edited parameter of <td><input type="text" placeholder={location} /> </td> to the top level function editById. the updated paramater is not being sent. I am new to react, so please bear with me. but thanks for the help all! :)
semantics really matters, why do you use a table if you can use a form.
look, I found couple of things
first when you click the button you need to prevent the default
e.preventDefault()
when you send data to the backend you need to send an Stringified JSON.
set the content-type to application/json
import React from "react";
import axios from "axios";
import "../styles/TourPage.css";
class TourPage extends Component {
constructor(props) {
super(props);
this.state = {
myData: [],
isLoading: true
};
}
componentDidMount() {
axios
.get("/getResults")
.then((res) => {
this.setState({
myData: res.data
});
})
.catch((error) => {
// Handle the errors here
console.log(error);
})
.finally(() => {
this.setState({
isLoading: false
});
});
}
deleteById = (id) => {
console.log(id)
axios
.post(`/deleteDoc`, {id: id} )
.then(() => {
console.log(id, " worked")
window.location = "/tour"
})
.catch((error) => {
// Handle the errors here
console.log(error);
})
}
editById = (id, location, Services, cnum) => {
console.log(id, location, Services, cnum)
axios
.post(`/editDoc`, JSON.stringify({id: id, location: location, Services: Services, cnum: cnum}),{
headers: {
"Content-Type": "Application/json"
}
} )
.then(() => {
console.log(id, " worked")
window.location = "/tour"
})
.catch((error) => {
// Handle the errors here
console.log(error);
})
}
render() {
// You can handle the loader part here with isLoading flag. In this case No data found will be shown initially and then the actual data
let { myData, isLoading } = this.state;
return (
<table id="customers">
<tr>
<th>siteLocation</th>
<th>Services</th>
<th>cnum</th>
</tr>
{myData.length > 0
? myData.map(({ location, Services, cnum, _id }, index) => (
<tr key={index}>
<td><input type="text" placeholder={location} /> </td>
<td>{Services}</td>
<td>{cnum}</td>
<button
onClick={(e) => {
e.preventDefault();
this.deleteById(_id);
}}
disabled={isLoading}
>
Delete
</button>
<button
onClick={() => this.editById(_id, location, Services, cnum)}
disabled={isLoading}
>
Submit Edit
</button>
</tr>
))
: "No Data Found"}
</table>
);
}
}
export default TourPage;
The problem is that you're not updating the state when you type into the input fields, so when you send the request to /editDoc you're sending the old data.
You need to listen to the onInput event on your input fields like so:
return (
<table id="customers">
<tr>
<th>siteLocation</th>
<th>Services</th>
<th>cnum</th>
</tr>
{myData.length > 0
? myData.map(({ location, Services, cnum, _id }, index) => (
<tr key={index}>
<td><input
type="text"
placeholder={location}
onInput={(e) => this.setState(prevState => ({
...prevState,
myData: [
...prevState.myData,
[index]: {
...prevStep.myData[index],
location: e.target.value
}
]
}))}
/></td>
<td>{Services}</td>
<td>{cnum}</td>
<button
onClick={() => this.deleteById(_id)}
disabled={isLoading}
>
Delete
</button>
<button
onClick={() => this.editById(_id, this.state.myData[index].location, Services, cnum)}
disabled={isLoading}
>
Submit Edit
</button>
</tr>
))
: "No Data Found"}
</table>
);
Note: this is not tested, but it should work

optimistic ui updates - react

I imagine this is a basic in react but I'm not sure how to get it to work, basically when I delete, create or edit anything in my components I want the change to happen in realtime without refreshing the page, I've achieved it at some level with the search function but not entirely sure how to do with for the delete function for example:
Here is what I'm working with, how would I get this to work with my axios delete function?
Thanks
import { connect } from 'react-redux';
import { fetchTournaments } from '../actions/tournaments';
import Item from './Item';
import EditTournament from './EditTournament';
import axios from 'axios';
import '../styles/Item.css';
class SearchAndDisplay extends React.PureComponent {
componentDidMount() {
this.props.fetchTournaments();
}
state = {
searchCriteria: '',
isLoading: false
};
handleChange = event => {
this.setState({
searchCriteria: event.target.value
});
};
async handleDelete(id) {
const url = `http://localhost:4000/tournaments/`;
await axios
.delete(url + id)
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});
}
formatDate(date) {
let options = {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
hour12: false
};
let newDate = new Date(Date.parse(date));
let format = new Intl.DateTimeFormat('default', options).format(newDate);
return format;
}
handleChange = event => {
this.setState({ searchCriteria: event.target.value });
};
renderList() {
let tournmentsArray = this.props.tournaments;
const filterTournaments = tournmentsArray.filter(item =>
item.name.includes(this.state.searchCriteria)
);
if (filterTournaments === undefined || filterTournaments.length === 0) {
return (
<React.Fragment>
<div className="notFound">
Something went wrong.
<br />
<button
className="notFoundButton"
onClick={() => {
this.setState({ searchCriteria: '' });
}}
>
Retry
</button>
</div>
</React.Fragment>
);
} else {
return filterTournaments.map(item => (
<Item
key={item.name}
name={item.name}
organizer={item.organizer}
participants={Object.values(item.participants)}
game={item.game}
start={this.formatDate(item.startDate)}
>
<div className="buttonBar">
<EditTournament id={item.id} />
<button
className="button"
onClick={() => {
if (
window.confirm('Are you sure you want to delete this item?')
) {
this.handleDelete(item.id);
}
}}
>
Delete
</button>
</div>
</Item>
));
}
}
render() {
return (
<div className="container">
<input
onChange={this.handleChange}
className="input"
placeholder="Search..."
id="searchField"
value={this.state.searchCriteria}
/>
<div className="row">{this.renderList()}</div>
</div>
);
}
}
function mapStateToProps({ tournaments }) {
return {
tournaments: Object.values(tournaments).flat()
};
}
export default connect(mapStateToProps, {
fetchTournaments
})(SearchAndDisplay);
unlike delete the create and edit data is handled by redux like so:
Create tournament:
import { reduxForm, Field } from 'redux-form';
import '../styles/promptForms.css';
import '../styles/Header.css';
import { connect } from 'react-redux';
import { createTournaments } from '../actions/tournaments';
class CreateTournamentPromptFrom extends React.Component {
constructor(props) {
super(props);
this.state = {
showHide: false
};
}
createTournamentButton() {
return (
<div>
<button
className="genericButton"
onClick={() => this.setState({ showHide: true })}
>
CREATE TOURNAMENT
</button>
</div>
);
}
renderInput = ({ input, label }) => {
return (
<div>
<label>{label}</label>
<br />
<input className="promptInput" {...input} autoComplete="off" />
</div>
);
};
onSubmit = formValues => {
this.props.createTournaments(formValues);
};
render() {
const { showHide } = this.state;
return (
<React.Fragment>
<div className={`overlay ${showHide ? 'toggle' : ''} `} />
<div className={`promptBox ${showHide ? 'toggle' : ''} `}>
<h3>localhost:3000 says</h3>
<form onSubmit={this.props.handleSubmit(this.onSubmit)}>
<Field
name="name"
component={this.renderInput}
label="Enter Tournament:"
/>
<button className="okayButton">OK</button>
</form>
<button
className="cancelButton"
onClick={() => this.setState({ showHide: false })}
>
Cancel
</button>
</div>
{this.createTournamentButton()}
</React.Fragment>
);
}
}
const formWrapped = reduxForm({
form: 'promptForm'
})(CreateTournamentPromptFrom);
export default connect(null, { createTournaments })(formWrapped);
actions:
import {
FETCH_TOURNAMENTS,
FETCH_TOURNAMENT,
CREATE_TOURNAMENT,
EDIT_TOURNAMENT
} from './types';
import { API_TOURNAMENTS_URL } from '../constants/api';
import axios from 'axios';
export const fetchTournaments = () => async dispatch => {
const response = await axios.get(API_TOURNAMENTS_URL);
dispatch({
type: FETCH_TOURNAMENTS,
payload: response.data.flat()
});
};
export const fetchTournament = id => async dispatch => {
const response = await axios.get(`http://localhost:4000/tournaments/${id}`);
dispatch({ type: FETCH_TOURNAMENT, payload: response.data });
};
export const createTournaments = formValues => async dispatch => {
const response = await axios.post(API_TOURNAMENTS_URL, {
...formValues
});
dispatch({ type: CREATE_TOURNAMENT, payload: response.data });
};
export const editTournaments = (id, formValues) => async dispatch => {
const response = await axios.patch(
`http://localhost:4000/tournaments/${id}`,
formValues
);
dispatch({ type: EDIT_TOURNAMENT, payload: response.data });
};
reducers:
import _ from 'lodash';
import {
FETCH_TOURNAMENT,
CREATE_TOURNAMENT,
FETCH_TOURNAMENTS,
EDIT_TOURNAMENT,
DELETE_TOURNAMENT
} from '../actions/types';
export default (state = {}, action) => {
switch (action.type) {
case FETCH_TOURNAMENT:
return { ...state, [action.payload.id]: action.payload };
case FETCH_TOURNAMENTS:
return { ...state, [action.payload.id]: action.payload };
case CREATE_TOURNAMENT:
return { ...state, [action.payload.id]: action.payload };
case EDIT_TOURNAMENT:
return { ...state, [action.payload.id]: action.payload };
case DELETE_TOURNAMENT:
return _.omit(state, action.payload);
default:
return state;
}
};
To "optimistically" delete an item from state you'll need to immediately delete it from state to reflect the change right away in the UI. BUT you will need to add extra redux state to "hold" a pending delete with your backend. When the delete is successful you clear the held delete, if it fails you clear the held delete and add it back in to your regular data (and perhaps display some error message or toast, etc..).
I see you don't do the delete via redux, so use local component state and you'll have to filter your tournament data when rendering.
class SearchAndDisplay extends PureComponent {
componentDidMount() {
this.props.fetchTournaments();
}
state = {
searchCriteria: "",
isLoading: false,
optimisticTournaments: null // <-- state to hold temp "deleted" data
};
handleChange = event => {
this.setState({
searchCriteria: event.target.value
});
};
async handleDelete(id) {
console.log("delete id", id);
// optimistically remove element
this.setState({
optimisticTournaments: this.props.tournaments.filter(
item => item.id !== id
)
});
await axios
.delete(url + id)
.then(res => {
console.log(res.data);
// Need to create a call back to let parent know element was deleted
this.props.deleteSuccess(id);
})
.catch(err => {
console.log(err);
alert("Failed to delete");
})
.finally(() => {
this.setState({ optimisticTournaments: null });
});
}
formatDate(date) {
let options = {
year: "numeric",
month: "numeric",
day: "numeric",
hour: "numeric",
minute: "numeric",
second: "numeric",
hour12: false
};
let newDate = new Date(Date.parse(date));
let format = new Intl.DateTimeFormat("default", options).format(newDate);
return format;
}
handleChange = event => {
this.setState({ searchCriteria: event.target.value });
};
renderList() {
let tournmentsArray =
this.state.optimisticTournaments || this.props.tournaments;
const filterTournaments = tournmentsArray.filter(item =>
item.name.includes(this.state.searchCriteria)
);
if (filterTournaments === undefined || filterTournaments.length === 0) {
return (
<React.Fragment>
<div className="notFound">
Something went wrong.
<br />
<button
className="notFoundButton"
onClick={() => {
this.setState({ searchCriteria: "" });
}}
>
Retry
</button>
</div>
</React.Fragment>
);
} else {
return filterTournaments.map(item => (
<Item
key={item.name}
name={item.name}
organizer={item.organizer}
participants={Object.values(item.participants)}
game={item.game}
start={this.formatDate(item.startDate)}
>
<div className="buttonBar">
<EditTournament id={item.id} />
<button
className="button"
onClick={() => {
if (
window.confirm("Are you sure you want to delete this item?")
) {
this.handleDelete(item.id);
}
}}
>
Delete
</button>
</div>
</Item>
));
}
}
render() {
return (
<div className="container">
<input
onChange={this.handleChange}
className="input"
placeholder="Search..."
id="searchField"
value={this.state.searchCriteria}
/>
<div className="row">{this.renderList()}</div>
</div>
);
}
}
Here is how you can do using forceUpdate() (Since you don't want to use state):
import React, { Component } from 'react';
import { render } from 'react-dom';
class App extends Component {
constructor() {
super();
this.items = [
{id: 1, name: "item 1"},
{id: 2, name: "item 2"},
];
this.handleDelete = this.handleDelete.bind(this);
}
handleDelete(index) {
const newState = [...this.items];
delete newState[index];
// or
// newState.splice(index, 1);
this.items = newState;
this.forceUpdate();
}
render() {
return (
<div>
{
this.items.map((item, index) => {
return (
<div>
{item.name}
<button onClick={() => this.handleDelete(index)}>Delete item</button>
</div>
)
})
}
</div>
);
}
}
render(<App />, document.getElementById('root'));
Just pass the index in the map method :
...map((item, index) => ...);
Do it in the then() after your axios call.
Note that the documentation highly advice you to avoid using forceUpdate() when you can, so you really should use a state for this, I don't see any good reason for you not to use it here.
Here is a quick repro on Stackblitz.

ASP.NET Core API and React JS

I have created ASP.NET Core API and React CURD practice example. I am following this example
but I've used react semantic ui for view. I am new to react and ASP.NET any suggestion so that I can improve my code.
I am able to fetch,POST,PUT and DELETE customer record but there are some small issues or point that I don't know how to implement. Those are as following
1 - I have used Modal so I can open form as popup (AddCustomer is form to add and edit record) in that I have two functions to OPEN and CLOSE the Modal but I don't how to call them from Customer.js and also on successful POST,PUT, DELETE request.
2 - When I open FORM to ADD or EDIT record I am not able to store that in state. When I try to type in input field it does not store in name and address.
3 - Also you can see in Customer.js I am hiding the form and delete modal but I want to close them on POST, PUT and DELETE task completion.
This is Customer.js
import React from 'react';
import AddCustomer from './AddCustomer';
import CustomerView from './CustomerView';
import DeleteRecord from './DeleteRecord';
export default class Customer extends React.Component {
constructor(props) {
super(props);
this.state = {
isAddCustomer:false,
isEditCustomer:false,
isDeleteCustomer:false,
closeForm:false,
singleCustomer:{},
deleteId:{}
}
}
onCreate = () => {
console.log("is add customer true ")
this.setState({isAddCustomer:true})
}
onFormControl = () =>{
this.setState({
isAddCustomer:false,
isEditCustomer:false
})
}
onDeleteClick = customerId => {
const headerTitle = "Customer";
console.log("onDeleteClick")
this.setState({
isDeleteCustomer:true,
deleteId:{
ID:customerId,
title:headerTitle,
open:true
}
});
}
//New Customer record
onAddFormSubmit = data => {
console.log("In add form submit")
console.log(data)
let customerApi = 'https://localhost:44387/api/Customers';
let method = '';
if(this.state.isEditCustomer){
console.log("In Edit api")
console.log(this.state.editCustomerId)
customerApi = 'https://localhost:44387/api/Customers/' + this.state.editCustomerId;
method = 'PUT'
}else{
console.log("In Add api")
customerApi = 'https://localhost:44387/api/Customers';
method = 'POST'
}
const myHeader = new Headers({
'Accept':'application/json',
'Content-type':'application/json'
});
fetch(customerApi,{
method:method,
headers:myHeader,
body:JSON.stringify(data)
})
.then(res => res.json())
.then(
(result) => {
this.setState({
users:result,
isAddCustomer:false,
isEditCustomer:false
})
},(error) => {
this.setState({ error });
}
)
}
//Edit customer record
onEditCustomer = customerId => {
//Get ID, name and address
this.setState({
editCustomerId:customerId
});
const customerApi = 'https://localhost:44387/api/Customers/'+customerId;
const myHeader = new Headers({
'Accept':'application/json',
'Content-type':'application/json; charset=utf-8'
});
fetch(customerApi,{
method:'GET',
headers:myHeader
})
.then(res => res.json())
.then(
(result) => {
this.setState({
isEditCustomer:true,
isAddCustomer:false,
singleCustomer:{
customer:result,
isEditCustomer:true
}
})
},(error) => {
this.setState({ error });
}
)
}
//Delete Customer
onDeleteCustomer = customerId => {
const customerApi = 'https://localhost:44387/api/Customers/'+customerId;
const myHeader = new Headers({
'Accept':'application/json',
'Content-type':'application/json; charset=utf-8'
});
fetch(customerApi,{
method:'DELETE',
headers:myHeader
})
.then(res => res.json())
.then(
(result) => {
this.setState({
isDeleteCustomer:false
})
},(error) => {
this.setState({ error });
}
)
}
render() {
let form;
if(this.state.isAddCustomer && !this.state.isEditCustomer){
console.log("Add")
form = <AddCustomer onAddFormSubmit={this.onAddFormSubmit}
isAddCustomer = {this.state.isAddCustomer}
onFormControl = {this.onFormControl}/>
}else if(this.state.isEditCustomer && !this.state.isAddCustomer){
console.log("Edit")
form = <AddCustomer onAddFormSubmit={this.onAddFormSubmit}
singleCustomer = {this.state.singleCustomer}
onFormControl = {this.onFormControl}/>
}else if(this.state.isDeleteCustomer){
console.log("Delete")
console.log(this.state.deleteId)
form = <DeleteRecord onDeleteCustomer={this.onDeleteCustomer}
deleteId = {this.state.deleteId}
/>
}
return (
<div>
{form}
<br/>
<CustomerView
onEditCustomer = {this.onEditCustomer}
onCreate = {this.onCreate}
onDeleteClick = {this.onDeleteClick}/>
</div>
)
}
}
Here is CustomerView.js
import React from 'react';
import { Table, Button } from 'semantic-ui-react';
export default class CustomerView extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
deleteTitle: "customer",
isLoaded: false,
formClose: false,
singleCustomer: [],
users: []
}
}
//fetch data
componentDidMount() {
const customerApi = 'https://localhost:44387/api/Customers';
const myHeader = new Headers();
myHeader.append('Content-type', 'application/json');
myHeader.append('Accept', 'application/json');
myHeader.append('Origin', 'https://localhost:44387');
const options = {
method: 'GET',
myHeader
};
fetch(customerApi, options)
.then(res => res.json())
.then(
(result) => {
this.setState({
users: result,
isLoaded: true
});
},
(error) => {
this.setState({
isLoaded: false,
error
});
}
)
}
//Delete Customer
onDeleteCustomer = customerId => {
const { users } = this.state;
this.setState({
users: users.filter(customer => customer.customerId !== customerId)
});
const customerApi = 'https://localhost:44387/api/Customers/' + customerId;
const myHeader = new Headers({
'Accept': 'application/json',
'Content-type': 'application/json; charset=utf-8'
});
fetch(customerApi, {
method: 'DELETE',
headers: myHeader
})
.then(res => res.json())
.then(
(result) => {
this.setState({
})
}, (error) => {
this.setState({ error });
}
)
}
render() {
const { users } = this.state;
return (
<div>
<Button color='blue' onClick={() => this.props.onCreate()}>New Customer</Button>
<br/>
<br/>
<Table celled textAlign='center'>
<Table.Header>
<Table.Row>
<Table.HeaderCell>ID</Table.HeaderCell>
<Table.HeaderCell>Name</Table.HeaderCell>
<Table.HeaderCell>Address</Table.HeaderCell>
<Table.HeaderCell>Action</Table.HeaderCell>
<Table.HeaderCell>Action</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body >
{
users.map(user => (
<Table.Row key={user.customerId}>
<Table.Cell>{user.customerId}</Table.Cell>
<Table.Cell>{user.name}</Table.Cell>
<Table.Cell>{user.address}</Table.Cell>
<Table.Cell>
<Button color='blue' onClick={() =>
this.props.onEditCustomer(user.customerId)}>Edit</Button>
</Table.Cell>
<Table.Cell>
<Button color='red' onClick={() =>
this.props.onDeleteClick(user.customerId)}>Delete</Button>
</Table.Cell>
</Table.Row>
))
}
</Table.Body>
<Table.Footer>
<Table.Row>
<Table.HeaderCell colSpan='5'>
No of Pages
</Table.HeaderCell>
</Table.Row>
</Table.Footer>
</Table>
</div>
)
}
}
Here is AddCustomer.js
import React from 'react';
import { Button, Form, Modal } from 'semantic-ui-react';
export default class AddCustomer extends React.Component {
constructor(props) {
super(props);
this.state = {
showCreateForm: false,
addOrdit:false,
id: "",
name: "",
address: "",
formData: {},
record: {}
}
if (props.isAddCustomer){
this.state.showCreateForm = props.isAddCustomer;
}
else if (props.singleCustomer) {
console.log("Single customer")
console.log(props.singleCustomer)
this.state.id = props.singleCustomer.customer.customerId;
this.state.name = props.singleCustomer.customer.name;
this.state.address = props.singleCustomer.customer.address;
this.state.record = props.singleCustomer.customer;
this.state.showCreateForm = props.singleCustomer.isEditCustomer;
this.state.addOrdit = props.singleCustomer.isEditCustomer;
console.log(this.state.name)
}else if(props.closeForm){
this.state.showCreateForm = props.closeForm;
}
}
handleChangeName = event => {
const value = event.target.value;
this.setState({ name:value });
}
handleChangeAddress = event => {
const value = event.target.value;
this.setState({ address:value });
}
handleSubmit = event => {
event.preventDefault();
if(this.state.addOrdit){
this.setState({
record: {
customerId: this.state.id,
name: this.state.name,
address: this.state.address
}
});
this.props.onAddFormSubmit(this.state.record);
}else{
this.setState({
formData: {
name: this.state.name,
address: this.state.address
}
});
this.props.onAddFormSubmit(this.state.formData);
}
}
//On cancel button click close Create user form
closeCreateForm = () => {
this.setState({ showCreateForm: false })
this.props.onFormControl();
}
//Open Create new Customer form
openCreateCustomer = () => {
this.setState({ showCreateForm: true })
}
render() {
let formTitle;
if (this.state.id !== 0) {
formTitle = "Edit Customer";
} else {
formTitle = "New Customer";
}
return (
<div>
<Modal size='small'
closeOnTriggerMouseLeave={false}
open={this.state.showCreateForm}>
<Modal.Header>
{formTitle}
</Modal.Header>
<Modal.Content>
<Form onSubmit={this.handleSubmit}>
<Form.Field>
<label>Name</label>
<input type="text" placeholder='Name' name="name"
value={this.state.name}
onChange={this.handleChangeName} />
</Form.Field>
<Form.Field>
<label>Address</label>
<input type="text" placeholder='Address' name="address"
value={this.state.address}
onChange={this.handleChangeAddress} />
</Form.Field>
<br />
<Button type='submit' floated='right' color='green'>Create</Button>
<Button floated='right' onClick={this.closeCreateForm}
color='black'>Cancel</Button>
<br />
</Form>
</Modal.Content>
</Modal>
</div>
)
}
}
And last one DeleteRecord.js
import React from 'react';
import { Button, Modal, Icon } from 'semantic-ui-react';
export default class DeleteRecord extends React.Component {
constructor(props) {
super(props);
this.state = {
ID:'',
title: "",
open: false
}
if(props.deleteId){
console.log(props.deleteId)
this.state.ID = props.deleteId.ID;
this.state.title = props.deleteId.title;
this.state.open = props.deleteId.open;
}
}
//On cancel button click close Create user form
closeCreateForm = () => {
console.log("Clicked")
this.setState({ open: false })
}
//Open Create new Customer form
openCreateCustomer = () => {
this.setState({ open: true })
}
render() {
const title = "Delete " + this.state.title;
return (
<div>
<Modal size='small'
closeOnTriggerMouseLeave={false}
open={this.state.open}>
<Modal.Header>
{title}
</Modal.Header>
<Modal.Content>
<br />
Are you sure?
<br />
<br />
<Button floated='right' icon labelPosition='right' color='red'
value='true'
onClick={() => this.props.onDeleteCustomer(this.state.ID)}
>
<Icon name='close' />
Delete
</Button>
<Button floated='right' color='black'
value='false'
onClick={this.closeCreateForm}
>Cancel</Button>
<br />
<br />
</Modal.Content>
</Modal>
</div>
)
}
}
Try using mobx for managing state variables and axios for making calls to API this will resolve your problem.
sample example code for using mobx
import { observable, computed } from "mobx"
class OrderLine {
#observable price = 0
#observable amount = 1
#computed get total() {
return this.price * this.amount;
}
}
now you can import OrderLine class in your Js and you can use and manage the state of price, amount dynamically for rendering the UI
Go through below link
https://mobx.js.org/README.html

Avoid navigation in react.js on button click

I am very new to react.js and trying to create a react component to render a json response from a REST API created in Python-Flask on button click.
Everything works fine but I am being navigated to the same page again and output which is a table does not persist.
We can see the console shows navigation back to the same page, which resets the component's state.
Snapshot of the console output shows the behavior
My component code:
var cols = [
{ key: 'id', label: 'Id' },
{ key: 'owner', label: 'Owner' },
{ key: 'path', label: 'Path' },
{ key: 'description', label: 'Description' }
];
class SearchForm extends React.Component {
constructor(props) {
super(props);
this.state = {items: [], searchString: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({searchString: event.target.value});
console.log(this.state.items);
}
handleSubmit(event) {
// alert('A name was submitted: ' + this.state.searchString);
// event.preventDefault();
// this.getMoviesFromApiAsync();
console.log(this.state.searchString);
this.getData();
}
getData() {
// Todo: Append the searchstring to the URI
fetch("http://localhost:5000/search")
.then(response => response.json())
.then(json => {
console.log("Inside request: ");
console.log(json.Data);
this.setState({
items: json.Data
});
console.log("after copy to state");
console.log(this.state.items);
});
}
generateRows() {
var cols = this.props.cols, // [{key, label}]
data = this.state.items;
console.log("Inside functions");
console.log(data);
// console.log(data);
return data.map(function(item) {
// handle the column data within each row
var cells = cols.map(function(colData) {
// colData.key might be "firstName"
return <td key={colData.key}> {item[colData.key]} </td>;
});
return <tr key={item.id}> {cells} </tr>;
});
}
generateHeaders() {
var cols = this.props.cols; // [{key, label}]
// generate our header (th) cell components
return cols.map(function(colData) {
return <th key={colData.key}> {colData.label} </th>;
});
}
render() {
var headerComponents = this.generateHeaders(),
rowComponents = this.generateRows();
return (
<div>
<form onSubmit={this.handleSubmit.bind(this)}>
<input type="text" value={this.state.searchString} onChange={this.handleChange.bind(this)} />
<input type="submit" value="Search" />
</form>
<br />
<div class="table-responsive">
<table class="table">
<thead> {headerComponents} </thead>
<tbody> {rowComponents} </tbody>
</table>
</div>
</div>
);
}
}
module.exports = SearchForm;
const main = document.getElementById('main');
ReactDOM.render(<SearchForm cols={cols}/>, main);
Formatting this as an answer for future reference. When using a form, the event handler for form submission needs to have
event.preventDefault()
in order to keep the default form submission and redirect from happening.
Reference

Resources