I am trying to reset the state for an object stored in my users array on click with handleDelete after I remove from the database. However, my state is not changing. I am able to log the current user with console.log('found: ' + this.state.users[i]). Basically, I have a table populated from my API and am trying to remove the row for the state without refreshing the page, but the state is not updating.
The constructor where my initial state is stored:
constructor(props) {
super(props);
this.state = {
users: []
}
this.handleDelete = this.handleDelete.bind(this);
};
Grabbing the API on mount:
componentDidMount() {
fetch('/myAPI')
.then(res => res.json())
.then(users => this.setState({ users }));
}
Mapping over data stored in state from fetch
render() {
return (
<tbody>
{this.state.users.map(user =>
<tr key={user.uniqueid}>
<td>{user.name}</td>
<td>{user.versions}</td>
<td>{user.type}</td>
<td>{user.hours}</td>
<td>{user.refresh}</td>
<td>{user.uniqueid}</td>
<td>{user.date}</td>
<td><Button onClick={this.handleDelete} data-id={user.uniqueid}><FaTrashO /></Button></td>
</tr>
)}
</tbody>
);
}
delete handler where I am TRYING to reset state for :
handleDelete(e) {
let dataId = e.target.getAttribute('data-id');
axios({
method: 'delete',
responseType: 'json',
url: '/myAPI',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Access-Control-Allow-Methods': "GET,HEAD,OPTIONS,POST,PUT"
},
data: { _id: dataId }
})
.then((response) => {
console.log(dataId + ' deleted with axios')
for (let i = 0; i < this.state.users.length; i++){
if (dataId === this.state.users[i]._id) {
let currentObj = this.state.users[i];
console.log('found: ' + this.state.users[i])
this.setState((prevState) => {
currentObj._id = ''
currentObj.date = '',
currentObj.hours = '',
currentObj.name = '',
currentObj.refresh = '',
currentObj.type = '',
currentObj.uniqueid = '',
currentObj.versions = ''
});
}
}
})
.catch((err) => {
throw err;
})
}
Example of what im calling from my API:
[
{
_id: "XJAbmHCX",
name: "an_example_2",
type: "B",
versions: "10",
hours: "10",
refresh: "Yes",
uniqueid: "XJAbmHCX",
date: "2018/01/08",
__v: 0
},
{
_id: "TOoIi7xS",
name: "test",
type: "A",
versions: "10",
hours: "10",
refresh: "Yes",
uniqueid: "TOoIi7xS",
date: "2018/01/09",
__v: 0
},
{
_id: "oeaigjesroigj",
name: "an_example_2_1",
type: "B",
versions: "10",
hours: "10",
refresh: "Yes",
uniqueid: "oeaigjesroigj",
date: "2018/01/08",
__v: 0
}
]
In the for loop of handleDelete, I simply sliced the user adn returned every object without the current ID to the state
for (let i = 0; i < this.state.users.length; i++){
if (dataId === this.state.users[i]._id) {
let users = this.state.users.slice();
users = users.filter(u => { return u._id !== dataId; });
this.setState({ users: users });
}
}
Related
I have a question form where the administrator can choose whether the question will be objective or multiple choice, but when the user marks 2 checkboxes, I pass the ID to the API and it cannot receive an array just an integer. I need to separate the array and pass it unitarily
PAYLOAD
0: {survey: {id: "252"}, question: {id: "385"}, personSurvey: {id: "246"},…}
personSurvey: {id: "246"}
question:{id: "385"}
questionAlternative: {id: [["367", "369"]]}
survey: {id: "252"}`
My HandleSubmit
function handleSubmit(data: any) {
setLoading(true);
apiBase.create("answer/all", data.answer);
survey &&
apiBase
.find<IEventDetailDTO>(
"event-detail",
`typeDetail=ID&eventEventTypeId=3&idReference=${survey.id}`,
)
.then(
({ data: eventDetails }) =>
eventDetails[0] &&
apiBase.patch(
"event-detail",
eventDetails[0],
{ dateSurveyAnswered: nowDate() },
{ headers: { noMessage: true } },
),
);
apiBase
.patch(
"/person-survey",
{ id: personSurveyId },
{ statusTarget: "RESPONDIDO" },
{ headers: { noMessage: true } },
)
.then(() => setLoading(false));
}
FORM Component
const getValue = (choiceRef) => {
const values = choiceRef.filter((i) => i.checked).map((i) => i.value);
return [values];
};
I need the questionAlternative ID to be passed separately and that it not lose the question id reference
Currently im trying to switch over from useQuery to useInfiniteQuery but for some reason now it returns no data. The reason why I need to make the switch is to do infinite pagination. The 'details' paramater is an interface I made. This is what gets my data.
const getVendors = async (details: VendorSearchInterface) => {
// console.log()
try {
const axiosConfig: AxiosRequestConfig = {
method: 'GET',
url: `${config.apiHost}/vendors/getAllActiveVendors`,
headers: {
'Content-Type': 'application/json'
},
params: {
sameDayRelease: details.isSameDayRelease || null,
region: details.region === 'all' ? null : details.region,
name: details.name || null,
address: details.address || null,
// topVendors: details.region === 'TOP' ? 1 : null
page: details.page === false ? null : details.page,
count: details.count === false ? null : details.count
}
}
const resp: AxiosResponse = await axios(axiosConfig)
const data = resp.data.data?.map((vendor: any) => ({
vendorId: vendor.providerId,
displayName: vendor.name,
// Formatting phone numbers per Joey's request (US/CA only)
phone:
vendor.phone && vendor.region !== 'EU'
? vendor.phone.replace(/[^0-9]/g, '').replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3')
: vendor.phone,
line1: formatString(vendor.line1),
line2: formatString(vendor.line2),
city: formatString(vendor.city),
cityState: `${vendor.city} ${vendor.state} ${vendor.postalCode}
${vendor.station ? vendor.station : ''} ${vendor.stateFullName}`,
state: vendor.state.toUpperCase(),
postalCode: vendor.postalCode,
station: vendor.station,
region: vendor.region,
isSameDayRelease: !!vendor.isSameDayRelease,
addressId: vendor.addressId,
brand: vendor.brandCode,
isTopVendor: vendor.isTopVendor,
clientAcceptCreditCard: vendor.clientAcceptCreditCard
}))
if (data?.length === 0) {
handleError({ error: 'Unable to retreive list of vendors', title: '' })
return data
}
const vendors: VendorDetailsInterface[] = data
return vendors
} catch (error) {
if (axios.isAxiosError(error)) {
const { message } = error
handleError({ error: message, title: 'Error vendor details' })
return []
}
handleError({ error, title: 'Error vendor details' })
return []
}
}
function formatString(string: string) {
return string
? string
.split(' ')
.map((word: string) => {
const lowerCaseWord = word.toLowerCase()
return lowerCaseWord.charAt(0).toUpperCase() + lowerCaseWord.slice(1)
})
.join(' ')
: null
}
export default getVendors
This is my new useInfiniteQuery function im trying to receive the data from.
export const useGetVendorsQuery = (details: VendorSearchInterface) =>
useInfiniteQuery(
['vendorDetails',
{
isSameDayRelease: details.isSameDayRelease,
region: details.region,
name: details.name,
address: details.address,
count: details.count,
page: details.page
// topVendors: details.topVendors,
}],
() => getVendors(details),
{
getNextPageParam: (lastPageData) => lastPageData?.data.next_page_url
}
)
I have a question I am making React app. The thing is that in useEffect I loop through six items every time when only one thing changes. How to solve it to change only one variable which was changed in reducer function not looping for 6 items when only one was changed, or is it okay to keep code like this?
const initialReducerValue = {
name: {
val: '',
isValid: false,
},
lastName: {
vaL: '',
isValid: false
},
phoneNumber: {
val: '',
isValid: false
},
city: {
val: '',
isValid: false,
},
street: {
val: '',
isValid: false
},
postal: {
val: '',
isValid: false
},
}
const OrderForm = () => {
const orderReducer = (state, action) => {
if (action.type === 'HANDLE TEXT CHANGE') {
return {
...state,
[action.field]: {
val: action.payload,
isValid: true
}
}
}
}
const [formState, formDispatch] = useReducer(orderReducer, initialReducerValue)
const [formIsValid, setFormIsValid] = useState(false)
const changeTextHandler = (e) => {
formDispatch({
type: 'HANDLE TEXT CHANGE',
field: e.target.name,
payload: e.target.value
})
}
useEffect(() => {
const validationArray = []
for (const key of Object.keys(formState)) {
validationArray.push(formState[key].isValid)
}
const isTrue = validationArray.every(item => item)
setFormIsValid(isTrue)
}, [formState])
This code
const validationArray = []
for (const key of Object.keys(formState)) {
validationArray.push(formState[key].isValid)
}
const isTrue = validationArray.every(item => item)
is equivalent to
const isTrue = Object.values(formState).every(item => item.isValid);
This still iterates over all items when only one was changed, but with a temporary array less.
For six items, I would not spend time trying to optimize this code further, but that's your choice.
I need to get the array of handle change value and pass into the API URL. I'll share my code.
import React from 'react';
import Select from 'react-select';
const Selects = [
{
name: 'firstSelect',
options: [
{ value: 1, label: 'Vg' },
{ value: 2, label: 'sri' }
]
},
{
name: 'secondSelect',
options: [
{ value: 1, label: 'akila' },
{ value: 2, label: 'selvi' },
{ value: 3, label: 'shanmuga' }
]
}
];
export default class Demo extends React.Component {
onSelectChange(name, value) {
let obj = [];
obj[name] = value;
this.setState(obj);
console.log(obj[name].value);
let url =
'http://localhost:99999/api/GetProfile/Get_MyPostDetails?id=3&Year=' +
obj[name].value +
'&CategoryID=' +
obj[name].value;
let user = JSON.parse(localStorage.getItem('user'));
const accessToken = user;
console.log(accessToken);
//console.log("hi");
fetch(url, {
method: 'GET',
headers: {
'Content-type': 'application/json',
Accept: 'application/json',
Authorization: 'Bearer ' + accessToken,
'Access-Control-Allow-Headers': 'Access-Control-Request-Headers '
}
//body:JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
this.setState({
like: data
});
console.log('Filter', data);
// console.log(emps.profile_dateOfAnniversary);
});
}
render() {
return (
<div>
{Selects.map((select, i) => {
return (
<Select
key={i}
name={select.name}
options={select.options}
onChange={this.onSelectChange.bind(this, select.name)}
/>
);
})}
</div>
);
}
}
When I select the First dropdown value it passes into the Year and Category Id also. I need to select the first dropdown value pass into the year and the second value is set into the CategoryId. Please share your Idea.
Thanks in Advance.
this.setState is asynchronous
When your use state in API Url first time, your state is empty yet. When you do it second time state have data from first this.setState call.
Your must do API call in seState callback:
this.setState(
(prev) => {
return {
...prev,
[name]: {
...prev[name],
value: value.value
}
};
},
() => {
//state will be updated and you can send API call
}
);
Im using React table and loading a page which displays a table with data fetched from an API. Im also listening on a web socket and right now, whenever something is sent over a web socket, Im printing a console message. Now I want to reload the table(in turn making the API call) when I receive any update on the web socket.
class TableExp extends React.Component {
constructor() {
super();
this.state = {
tableData: [
{
resourceID: '',
resourceType: '',
tenantName: '',
dealerID: '',
status: '',
logFilePath: '',
supportPerson: '',
lastUpdatedTime: '',
},
],
//testMessage: [{ message: 'Initial Message' }],
};
}
componentDidMount() {
this.websocket = new WebSocket(socket);
this.websocket.onopen = () => {
axios.get('https://myapi.com', {
headers: {},
responseType: 'json',
})
.then((response) => {
this.setState({ tableData: response.data });
});
console.log('Socket Opened');
};
this.websocket.onmessage = (event) => {
const data = (JSON.parse(event.data));
const status = data.status;
console.log(data.status);
this.forceUpdate();
if (status === 'failed') {
console.log('Error message received');
this.reloadTable();
}
};
this.websocket.onclose = () => {
this.statusDispatcher('closed');
};
}
reloadTable() {
this.forceUpdate();
}
render() {
const { tableData } = this.state;
return (
<ReactTable
data={tableData}
noDataText="Loading.."
columns={[
{
columns: [
{
Header: 'Dealer ID',
accessor: 'dealerId',
id: "dealerId",
},
{
Header: 'Location',
id: "dealerId",
},
{
columns: [
{
filterable: false,
Header: 'File Path',
accessor: 'logFilePath',
},
{
filterable: false,
Header: 'Date',
accessor: 'Date',
},
],
},
]}
defaultPageSize={20}
style={{
height: '450px', // This will force the table body to overflow and scroll, since there is not enough room
}}
className="-striped -highlight"
/>
);
}
You can simple setState within onmessage
this.websocket.onmessage = (event) => {
let data = [];
const status = data.status;
if (status === 'failed') {
console.log('Error message received');
// And do nothing, or empty table
} else {
data = JSON.parse(event.data);
}
this.setState({ tableData: data });
};