mdbreact is showing an unexpected behaviour - javascript

I am using mdbreact package to make table for my data. It's having an action button in the last column which opens a modal for editing the data.
Scenario is
I loaded the table with initial data
And then applied some sorting on it
And now I click on the edit button to open the modal for editing the data
Now the sorting gets automatically removed and it's looking really weird that modal is opening and data is changing in the background.
What do I need ?
I don't want data to be changed on the backend. Also, I don't know how to store that sorted data in the state even as I am using mdbreact for the first time.
Here you can check the exact issue I am facing.
File where I am formatting data and adding event and action to each row:
import React from 'react'
import PayRatesTable from './PayRatesTable'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faPencilAlt, faAngleRight, faAngleLeft } from '#fortawesome/free-solid-svg-icons'
import { Button, Row, Col } from 'reactstrap'
const columns =
[
{
label: 'Certificate',
field: 'certificate',
sort: 'asc'
},
{
label: 'Speciality',
field: 'speciality',
sort: 'asc'
},
{
label: 'Pay Rate ($)',
field: 'pay_rate',
sort: 'disabled'
},
{
label: 'Weekend Pay Rate ($)',
field: 'weekend_pay_rate',
sort: 'disabled'
},
{
label: 'Action',
field: 'action',
sort: 'disabled'
}
]
const formatCertSpec = (data, certificates, handleModelClose) => {
var cert = []
data && data.map((item) => (
certificates && certificates.map((certs) => {
if (certs.id == item.certificateId) {
certs.specialities && certs.specialities.map((certSpec) => {
if (item.speciality == certSpec.id) {
cert.push({
certificate: certs.abbreviation,
speciality: certSpec.name,
pay_rate: item.payRateCents ? `$${(item.payRateCents / 100).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}` : '',
weekend_pay_rate: item.weekendPayRateCents ? `$${(item.weekendPayRateCents / 100).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}` : '',
action: <Button color="link" onClick={(event) => {
event.preventDefault()
handleModelClose({
certificate: certs.abbreviation,
speciality: certSpec.name,
id: item.id,
pay_rate: item.payRateCents / 100,
weekend_pay_rate: item.weekendPayRateCents / 100,
})}}>
<FontAwesomeIcon key="edit" className="ml-2" icon={faPencilAlt} />
</Button>
})
}
})
}
})
))
return cert
}
function AddPayRatesComp({
data,
certificates,
handleModelClose,
handleNextPrevTabs
}) {
const certAndSpecPayData = formatCertSpec(data, certificates, handleModelClose)
console.log(certAndSpecPayData)
return (
<div className="container-fluid">
<PayRatesTable
columns={columns}
certificates={certificates}
certs={certAndSpecPayData}
/>
<Row className="mb-2 text-center">
<Col className="col-md-3">
</Col>
<Button
type="button"
onClick={() => handleNextPrevTabs('prev')}
outline
color="secondary"
className="btn-rounded font-weight-bold py-1 mr-2 mt-2 col-sm-12 col-md-3"
><FontAwesomeIcon icon={faAngleLeft} /> Previous</Button>
<Button
type="button"
onClick={() => handleNextPrevTabs('next')}
outline
color="secondary"
disabled
className="btn-rounded font-weight-bold py-1 mr-2 mt-2 col-sm-12 col-md-3"
>Next <FontAwesomeIcon icon={faAngleRight} /></Button>
</Row>
</div>
);
}
export default AddPayRatesComp;
PayRatesTable.js
import React from 'react'
import { MDBDataTable } from 'mdbreact'
const PayRatesTable = ({ columns, certs }) => {
const data = {
columns: columns,
rows: certs
}
return (
<>
<MDBDataTable
striped
bordered
medium="true"
responsive
data={data}
order={['certificate', 'asc' ]}
/>
<style jsx global>{`
#import "../styles/bootstrap-custom/jsx-import";
.table thead:last-child{
display:none;
}
`}</style>
</>
);
}
export default PayRatesTable;
This is all that I can provide due to security issues.

Related

Map one item from array

I'm mapping an array to have the Link which gonna direct me to modify one row of the table
This is my DepotList Component :
import React from 'react';
import { Link } from 'react-router-dom';
import Table from '../../../Common/Table';
import { textFilter } from 'react-bootstrap-table2-filter';
const DepotList = props => {
const { depots } = props;
const columns = [
{
dataField: 'name',
text: 'nom depot',
},
{
dataField: 'adress',
text: 'adresse',
sort: true,
},
{
dataField: 'size',
text: 'Taille depot',
},
{
dataField: 'equipements',
text: 'Equipements',
},
{
dataField: 'updated',
text: 'Mis à jour',
},
{
dataField: '',
text: 'Actions',
formatter: () => {
return (
<>
{depots.map((depot, index) => (
<div>
<Link
className=""
to={`/gestion-depots/edit/${depot._id}`}
key={index}
>
{console.log(`index ${depot._id}`)}
Modifier
</Link>
</div>
))}
</>
);
},
},
];
return (
<>
<p>{depots.length} Depots</p>
{console.log('depotlist ----', depots)}
<Table data={depots} columns={columns} csv search filter />
</>
);
};
export default DepotList;
But I'm getting n links in every action row like this :
And if i click the link it works perfectly lol : first link first row , second link second row ..etc
Can anyone help me to fix this problem !!
This is the Table Component
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory, { Type } from "react-bootstrap-table2-editor";
import filterFactory, { textFilter } from "react-bootstrap-table2-filter";
import paginationFactory from "react-bootstrap-table2-paginator";
import ToolkitProvider, {
CSVExport,
Search
} from 'react-bootstrap-table2-toolkit';
const indication = () => {
return 'Oops! No data now! Please try again!';
};
const { ExportCSVButton } = CSVExport;
const { SearchBar } = Search;
const Table = props => {
const {
data,
columns,
striped,
hover,
condensed,
csv,
search,
clickAction,
isRowEvents,
filter,
cellEdit,
pagination
} = props;
const rowEvents = {
onClick: (e, row, rowIndex) => {
clickAction(row._id, rowIndex);
}
};
const selectRow = {
mode: "checkbox",
clickToSelect: true,
clickToEdit: true,
};
return (
<ToolkitProvider
keyField='_id'
data={data}
columns={columns}
exportCSV={csv}
search={search}
filter={filter}
cellEdit={cellEdit}
pagination={pagination}
>
{props => (
<div className='table-section'>
{csv && (
<div className='csv'>
<ExportCSVButton
className='input-btn custom-btn-secondary md'
{...props.csvProps}
>
Exporter CSV
</ExportCSVButton>
</div>
)}
{search && (
<div className='search'>
<SearchBar {...props.searchProps} />
</div>
)}
<BootstrapTable
{...props.baseProps}
keyField='_id'
data={data}
columns={columns}
striped={striped}
hover={hover}
condensed={condensed}
pagination={paginationFactory()}
cellEdit={cellEditFactory({
mode: "dbclick",
blurToSave: true,
nonEditableRows: () => [1, 2, 3],
})}
noDataIndication={indication}
rowEvents={isRowEvents ? rowEvents : null}
filter={filterFactory()}
/>
</div>
)}
</ToolkitProvider>
);
};
export default Table;
depots is probably an array and in the last index of your columns you are mapping it with "Modifier" as its inner text.
formatter: () => {
return (
<>
{depots.map((depot, index) => (
<div>
<Link
className=""
to={`/gestion-depots/edit/${depot._id}`}
key={index}
>
{console.log(`index ${depot._id}`)}
Modifier
</Link>
</div>
))}
</>
);
},
Can you also share the table component, and the depots array list.
You are mapping all your depots array in your formatter so in each row you got all the links
I'm not sure of the logic you implemented in your Table component but you probably can solve the problem changing your last element of columns in this way
{
dataField: '_id',
text: 'Actions',
formatter: (_id) => {
return (
<div>
<Link
className=""
to={`/gestion-depots/edit/${_id}`}
key={index}
>
{console.log(`index ${_id}`)}
Modifier
</Link>
</div>
);
},
},
all you have to change is the parameters that you are passing to formatter in your table component based on the datafield
or you can pass the whole item to formatter and do your extraction on the single item

Can i populate a formik initialValue field that is an array? i'm using the react multiselect dropdown here, pls how can i do this

** const initialValues AssignClass: [],**
**NOW IN THE MULTISELECT DROP DOWN COMPONENT, i have set up formik there to my best effort, take a look **
import { ErrorMessage, useField } from "formik";
import Multiselect from "multiselect-react-dropdown";
const optionsArray = [
{ name: "Option1", id: 1 },
{ name: "Daniel", id: 2 },
];
const AppMultiSelect = ({
label = "Assign Class(es)",
obscure = false,
extraClasses,
error,
touched,
onFieldTouched,
options,
onSelect,
onRemove,
...props
}) => {
const [field, meta, helpers] = useField(props);
console.log(helpers, " the helpers");
return (
<div className="flex flex-col cursor-pointer w-full z-50 p-[5px]">
<label className="text-[14px] text-[#7D8592] font-semibold mb-2">
{label}
</label>
<div className=" w-full text-[#DADADA] py-[7px] border border-[#D8E0F0] rounded-2xl focus:border-danger focus:ring-danger py-[12px] px-[14px]">
<Multiselect
options={options} // Options to display in the dropdown
selectedValues={null} // Preselected value to persist in dropdown
onSelect={(selectedList) => {
helpers.setValue(...field.value, selectedList);
console.log(selectedList, " you selected this");
}} // Function will trigger on select event
onRemove={(selectedItem) =>
console.log(field.value, " to be removed")
} // Function will trigger on remove event
displayValue="name" // Property name to display in the dropdown options
{...props}
/>
</div>
{/* {error && touched && (
<span className="text-[14px] text-accent">{error}</span>
)} */}
</div>
);
};
export default AppMultiSelect;
** so, as you see above, i'm using the setValue, but then, the field updates but it happens once, even if i keep selecting more items... thanks in advance, by the way, im doing the formik validation and the rest in another component called addTeacher, and using yup for the schema part **
AppMultiSelect
name="AssignClass"
options={[
{ name: "fred" },
{ name: "cere" },
{ name: "veee" },
{ name: "mmeee" },
{ name: "typ" },
{ name: "wewe" },
]}
/>

ReactJS: Unable to read event.target.value while creating a select menu

I am trying to create a custom menu select for my Algolia search based on the documentation here with a barebones example. I am using Tailwind and Headless UI for my component styling.
More specifically, I am trying to make this work with the ListBox component by Headless UI, which is documented here. My code is below:
import { connectMenu } from "react-instantsearch-dom";
import React, { useState, Fragment, useEffect } from "react";
import { Listbox, Transition } from "#headlessui/react";
import { CheckIcon, SelectorIcon } from "#heroicons/react/solid";
function classNames(...classes) {
return classes.filter(Boolean).join(" ");
}
const MobileDropdownS = ({ label, currentRefinement, refine, hide }) => {
const [selected, setSelected] = useState(true);
const items= [
{ value: 'category', label: 'Category' },
{ value: 'brand', label: 'Brand' },
{ value: 'color', label: 'Color' },
{ value: 'size', label: 'Size' },
]
if (hide) return null;
return (
<Listbox
onChange={(event) => {
refine(event.target.value);
setSelected(event.target.value);
}}
value={currentRefinement || ""}
>
{({ open }) => (
<div>
<Listbox.Label>{label}</Listbox.Label>
<div>
<Listbox.Button>
<span>{label}</span>
</Listbox.Button>
<Listbox.Options>
{items.map((item) => (
<Listbox.Option
key={item.label}
value={item.isRefined ? currentRefinement : item.value}
key={item.label}
className={({ active }) =>
classNames(
active ? "text-white bg-indigo-600" : "text-gray-900",
"cursor-default select-none relative py-2 pl-3 pr-9"
)
}
>
{({ selected, active }) => (
<>
<div className="flex items-center">
<span
className={classNames(
selected ? "font-semibold" : "font-normal",
"ml-3 block truncate"
)}
>
{item.label}
</span>
</div>
{selected ? (
<span
className={classNames(
active ? "text-white" : "text-indigo-600",
"absolute inset-y-0 right-0 flex items-center pr-4"
)}
>
<CheckIcon className="h-5 w-5" aria-hidden="true" />
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</div>
</div>
)}
</Listbox>
);
};
const MobileDropdownSelect = connectMenu(MobileDropdownS);
export default MobileDropdownSelect;
The way I understand it, ListBox becomes the <select> tag from Algolia's documentation, where I should add this:
refine(event.target.value);
setSelected(event.target.value);
However, this gives me the following error:
×
TypeError: Cannot read properties of undefined (reading 'value')
onChange
D:/Gatsby/XTheme/src/components/search/MobileDropdown.jsx:22
19 | <Listbox
20 | onChange={
21 | event => {
> 22 | refine(event.target.value)
23 | setSelected(event.target.value)
24 | }
25 | }
Is this not correct? How do I fix this error and port over Algolia's example with the <select> input to the <ListBox> component such that when I select an item from the Listbox, it refines the search based on the item?
Tru using event.currentTarget.value in place of event.target.value . You can find difference between both in this link

Popover does not show up in React

I am trying to make a webapplication with Treeviz dependency. The goal is to place a popover button to each node of the tree and if user clicks to the button he/she can see the description of the node,and after it should be editable. I tried in many ways but for me popover does not work in React.
There is an example for what I would like to do. You can see I have to insert React component to HTML therefor I am using renderToString. All you have to look is the renderNode property of the tree. I am referencing to React component in renderNode like: ${tooltip} ${popover}.
import React from "react";
import { TreevizReact } from "treeviz-react";
import { renderToString } from "react-dom/server";
const data_1 = [
{
id: 1,
text_1: "Chaos",
description: "Void",
father: null,
color: "#FF5722"
},
{
id: 2,
text_1: "Tartarus",
description: "Abyss",
father: 1,
color: "#FFC107"
},
{ id: 3, text_1: "Gaia", description: "Earth", father: 1, color: "#8BC34A" },
{ id: 4, text_1: "Eros", description: "Desire", father: 1, color: "#00BCD4" }
];
export const App = () => {
return (
<div style={{ marginLeft: 10 }}>
<div style={{ display: "flex" }}>
<TreevizReact
data={data_1}
relationnalField={"father"}
nodeWidth={120}
nodeHeight={80}
areaHeight={500}
areaWidth={1000}
mainAxisNodeSpacing={2}
secondaryAxisNodeSpacing={2}
linkShape={"quadraticBeziers"}
renderNode={(data) => {
const nodeData = data.data;
const settings = data.settings;
let result = "";
const tooltip = renderToString(
<strong
data-toggle="tooltip"
data-placement="top"
title={nodeData.description}
>
{nodeData.text_1}
</strong>
);
const popover = renderToString(
<button
type="button"
className="btn btn-secondary"
data-container="body"
data-toggle="popover"
data-placement="top"
data-content={nodeData.description}
>
Popover on top
</button>
);
if (data.depth !== 2) {
result = `<div className="box"
style='cursor:pointer;height:${settings.nodeHeight}px; width:${settings.nodeWidth}px;display:flex;flex-direction:column;justify-content:center;align-items:center;background-color:${nodeData.color};border-radius:5px;'>
<div>
${tooltip}
${popover}
</div></div>`;
} else {
result = `<div className="box" style='cursor:pointer;height:${
settings.nodeHeight
}px; width:${
settings.nodeHeight
}px;display:flex;flex-direction:column;justify-content:center;align-items:center;background-color:${
nodeData.color
};border-radius:${settings.nodeHeight / 2}px;'><div><strong>
${nodeData.text_1}
</strong></div></div>`;
}
return result;
}}
duration={600}
isHorizontal
linkWidth={(node) => 10}
/>
</div>
</div>
);
};
export default App;
Tooltip is working but popover does not show up.
You can try it: https://codesandbox.io/s/zealous-orla-4bq5f?file=/src/App.js
Also tried
const popover = renderToString(
<Popup
trigger={<button> Trigger</button>}
position="right center"
>
<form onSubmit={saveHandler}>
<ContentEditable
html={text.current}
onChange={handleChange}
/>
<button type="submit">Save</button>
<button>Cancel</button>
</form>
</Popup>
const popoverContent = (
<Popover id="popover-basic">
<Popover.Header as="h3">Popover right</Popover.Header>
<Popover.Body>
And here's some <strong>amazing</strong> content. It's very
engaging. right?
</Popover.Body>
</Popover>
);
const popover = renderToString(
<OverlayTrigger
trigger="click"
placement="right"
overlay={popoverContent}
>
<Button variant="success">Click me to see</Button>
</OverlayTrigger>
);
None of them worked for me.
Probably your approach doesn't work because the dom elements in the tree are created dynamically, and bootstrap doesn't set them up.
A more react-ish way to do it would be using react-bootstrap lib and managing every UI aspect in states. To implement the tooltip, the Overlay component actually as a prop called target that allows you to change over what element the tooltip is shown.
<Overlay target={tooltipTarget} show={showTooltip} placement="right">
{(props) => (
<Tooltip id="overlay-example" {...props}>
{tooltipNode?.data.text_1}
</Tooltip>
)}
</Overlay>
Then you only need to manage all these states in the onNodeMouseEnter and onNodeMouseLeave handlers in the TreevizReact component.
onNodeMouseEnter={(_event, node) => {
const t = document.querySelector(`#node-${node.id}`);
setTooltipTarget(t);
setShowTooltip(true);
setTooltipNode(node);
}}
onNodeMouseLeave={(_event, node) => {
setTooltipTarget(null);
setShowTooltip(false);
setTooltipNode(null);
}}
The popup follows the same logic with another set of states.
<div ref={ref}>
<Overlay
show={!!selectedNode.current}
target={target}
placement="bottom"
container={ref.current}
containerPadding={20}
>
<Popover id="popover-contained">
{/* hack to avoid weird blinking (due mutable state) */}
{!!selectedNode.current && (
<>
some form based on node data
{JSON.stringify(selectedNode.current?.data)}
</>
)}
</Popover>
</Overlay>
</div>
and in onNodeClick handler
onNodeClick={(_event, node) => {
const t = document.querySelector(`#node-${node.id}`);
// unselect if already selected
if (selectedNode.current?.id === node.id) {
selectedNode.current = null;
setTarget(null);
} else {
selectedNode.current = node;
setTarget(t);
}
}}
You might notice this time I used a mutable variable via a ref (selectedNode.current), for some reason using a state caused some issues, maybe due to D3 and react having different rendering cycles, reason why you'll probably encounter some other glitches in this implementation.
https://codesandbox.io/s/quizzical-buck-slofh?file=/src/App.js

Duplicate value of useRef current value after switching between tabs in react

If i switch between Transfer to Beneficiary and All Beneficiary tab the Select options get duplicated but if i change the second useEffect hook dependency to allBeneficiary.current instead of beneficiaries presently there, Select options doesnt duplicate, but the options are not rendered on the first render until I switch to All Beneficiary tab and back to Transfer Beneficiary
Below is the Transfer to Beneficiary code
// Hooks and Contexts
import React, { useState, useContext, useEffect, useRef } from "react";
import { TransferPointsContext } from "../../../../../context/TransferPoints";
import { LoaderContext } from "../../../../../context/Loading";
// Components
import TransferSummary from "../../../../common/modals/TransferSummary";
import Loading from "../../../../features/Loader/Loading";
// UI
import swal from "sweetalert";
import toastr from "toastr";
import Select from "react-select";
import "./css/transfer-points.css";
import { nanoid }from 'nanoid'
function TransferPoints() {
const [showTransferSummary, setShowTransferSummary] = useState(false);
const [transferSummaryData, setTransferSummaryData] = useState(false);
const [showBeneficiaryDataPage, setShowBeneficiaryDataPage] = useState(false);
const [checked, setChecked] = useState(false);
const [ options, setOptions ] = useState([])
const {
verifyCardNumber,
verifyCardState,
getBeneficiaryList,
beneficiaries, //list of beneficiaries from API
hideBeneficiaryDataPage,
setInputs,
inputs,
} = useContext(TransferPointsContext);
const { loading } = useContext(LoaderContext);
toastr.options.progressBar = true;
toastr.options = {
toastClass: "alert",
iconClasses: {
error: "alert-error",
info: "alert-info",
success: "alert-success",
warning: "alert-warning",
},
};
const allBeneficiaries = useRef([]);
useEffect(() => {
getBeneficiaryList();
}, [allBeneficiaries]);
useEffect(() => {
if (beneficiaries.data !== null) {
if (
beneficiaries.data.status === 0 &&
beneficiaries.data.success === false
) {
toastr.error("Failed to fetch user beneficiaries!", "error", {
iconClass: "toast-error",
});
console.log("beneficiaries", beneficiaries.data);
} else if (
beneficiaries.data.status === 1 &&
beneficiaries.data.success === true
) {
console.log('All beneficiary ', allBeneficiaries.current)
beneficiaries.data.data.forEach((beneficiary) => {
console.log('For each ', beneficiary)
allBeneficiaries.current.unshift({
value: beneficiary.membership_number,
label: `${beneficiary.first_name} ${beneficiary.last_name == null ? '' : beneficiary.last_name}`,
});
});
console.log('LENGTH ', allBeneficiaries.current.length)
}
}
}, [beneficiaries]);
useEffect(() => {
if (hideBeneficiaryDataPage) {
setShowBeneficiaryDataPage(false);
}
}, [hideBeneficiaryDataPage]);
const beneficiaryData = useRef({});
useEffect(() => {
if (verifyCardState.data !== null) {
if (
verifyCardState.data.status === 1 &&
verifyCardState.data.success === true
) {
setShowBeneficiaryDataPage(true);
beneficiaryData.current = {
name: `${verifyCardState.data.data.first_name} ${verifyCardState.data.data.last_name == null ? '' : verifyCardState.data.data.last_name}`,
};
toastr.success("Membership Id Validated!", "Success", {
iconClass: "toast-success",
});
return;
}
if (
verifyCardState.data.status === 0 &&
verifyCardState.data.success === false
) {
if (verifyCardState.data.message && !verifyCardState.data.data) {
toastr.error(verifyCardState.data.message, "Validation failed!", {
iconClass: "toast-error",
});
setShowBeneficiaryDataPage(false);
return;
}
setShowBeneficiaryDataPage(false);
const errorMessages = verifyCardState.data.data;
for (const error in errorMessages) {
toastr.error(errorMessages[error], "Validation Error!", {
iconClass: "toast-error",
});
}
return;
}
}
}, [verifyCardState]);
const handleSearchInput = (event) => {
const card_number = event.value;
setInputs((inputs) => ({
...inputs,
card_number,
}));
verifyCardNumber(card_number);
};
const proceedToTransfer = () => {
const amount = document.getElementById("amount").value;
if (amount.trim().length === 0) {
swal({
title: "Oops!",
text: `Amount field cannot be empty`,
icon: "error",
button: "Ok",
});
return;
}
setShowTransferSummary(!showTransferSummary);
setTransferSummaryData({
amount,
name: beneficiaryData.current.name,
membership_id: inputs.card_number,
save_beneficiary: (beneficiaryData.current.save_beneficiary == 1) ? 1 : 0,
});
};
const handleInputChange = (event) => {
event.persist();
setInputs((inputs) => ({
...inputs,
[event.target.name]: event.target.value,
}));
};
const handleChange = (event) => {
event.persist();
setChecked(event.target.checked);
const save_beneficiary = event.target.checked === true ? 1 : 0;
beneficiaryData.current.save_beneficiary = save_beneficiary;
};
console.log('LENGTH ', allBeneficiaries.current)
// console.log('current beneficiaries ', (allBeneficiaries.current) )
// console.log('CHECKED ', beneficiaryData.current.save_beneficiary )
// let id = nanoid()
return (
<div>
{/* {loading ? <Loading /> : ""} */}
<form action="#">
<div className="row">
<div className="col-md-12">
<div className="form-group">
<label htmlFor="acc-email">Select Beneficiary </label>
<Select
onChange={handleSearchInput}
className="basic-single"
classNamePrefix="select"
isClearable="true"
isSearchable="true"
name="beneficiary_card_number"
defaultValue="Select"
options={allBeneficiaries.current} //THIS RETURNS DUPLICATED VALUE ON NAVIGATING TO ALL BENEFICIARIES AND BACK
/>
</div>
<h6 class="mt-3 heading-border border-0">OR</h6>
<div className="row align-items-center justify-content-between">
<div className="col-md-8">
<label htmlFor="card_number">Enter Membership Id</label>
<input
type="text"
className="form-control"
name="card_number"
onChange={handleInputChange}
value={inputs.card_number}
/>
</div>
<div className=" col-4 " style={{marginTop: '30px', paddingLeft: '10px', textAlign: 'end',}}>
<button
onClick={() => verifyCardNumber(inputs.card_number)}
type="button"
className="btn-lg btn btn-primary"
>
Validate Id
</button>
</div>
</div>
</div>
{showBeneficiaryDataPage === true ? (
<div className="col-sm-12">
<h6 class="mt-3 heading-border border-0"></h6>
<div className="row">
<div className="col-md-6">
<div className="form-group">
<label htmlFor="acc-name">Name</label>
<input
type="text"
className="form-control"
id="acc-name"
required
disabled
name="acc-name"
value={beneficiaryData.current.name}
/>
</div>
</div>
<div className="col-md-6">
<div className="form-group">
<label htmlFor="acc-lastname">Membership Id</label>
<input
type="text"
className="form-control"
id="acc-lastname"
required
disabled
name="acc-lastname"
value={inputs.card_number}
/>
</div>
</div>
</div>
<div className="row">
<div className="col-md-12">
<div className="form-group">
<label htmlFor="acc-lastname">Amount</label>
<input
type="text"
className="form-control"
id="amount"
required
name="amount"
onChange={handleInputChange}
value={inputs.amount}
/>
</div>
</div>
</div>
<div class="form-check">
<input
class="form-check-input"
type="checkbox"
checked={checked}
name="save_beneficiary"
onChange={handleChange}
/>
<span className="ml-3 font-weight-bold terms-condition">
Save Beneficiary
</span>
</div>
<div className="mb-2"></div>
<div className="form-footer">
<div className="col-md-12 d-flex justify-content-center">
<button
onClick={() => proceedToTransfer()}
type="button"
className="btn-lg w-50 btn btn-primary"
>
Proceed
</button>
</div>
</div>
</div>
) : (
""
)}
</div>
</form>
{showTransferSummary === true ? (
<TransferSummary data={transferSummaryData} setShowTransferSummary={setShowTransferSummary} setShowBeneficiaryDataPage={setShowBeneficiaryDataPage}/>
) : (
""
)}
</div>
);
}
export default React.memo(TransferPoints);
This is the code for All Beneficiaries
import React, { useState, useContext, useEffect, useRef } from "react";
import "./css/transfer-points.css";
import { TransferPointsContext } from "../../../../../context/TransferPoints";
import Loading from "../../../../features/Loader/Loading";
import swal from "sweetalert";
import { LoaderContext } from "../../../../../context/Loading";
import toastr from "toastr";
import axios from 'axios'
import { ToastContainer, toast } from 'react-toastify';
function ShowAllBeneficiariesPage() {
const [ data, setData ] = useState([])
const {
getBeneficiaryList,
beneficiaries,
removeBeneficiary,
state,
} = useContext(TransferPointsContext);
const { loading } = useContext(LoaderContext);
toastr.options.progressBar = true;
toastr.options = {
toastClass: "alert",
iconClasses: {
error: "alert-error",
info: "alert-info",
success: "alert-success",
warning: "alert-warning",
},
};
const handleDelete = (id) => {
swal({
title: "Are you sure you want to remove beneficiary?",
text: "You won't be able to revert this!",
icon: "warning",
buttons: ["Cancel", "Proceed!"],
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result === true) {
removeBeneficiary(id);
console.log('ID OF RECEIVER ', id)
const newBeneficiary = data.filter(add => add.id !== id)
setData(newBeneficiary)
toastr.success("Beneficiary Removed !", "Success", {
iconClass: "toast-success",
});
}
});
};
const fetchData = () => {
axios.get(`user/beneficiaries`)
.then( res => setData(res.data.data ))
}
useEffect(() => {
fetchData()
}, [])
return (
<div>
{/* {loading ? <Loading /> : ""} */}
{ data.length === 0 ?
(
<div style={{textAlign: 'center'}}>No beneficiaries found</div>
)
:
(
<div className="col-sm-12">
{data.map((item) => {
console.log('Beneficiary Data ', data)
return (
<p className="mb-1 p-4 beneficiary-list">
{item.first_name} {item.last_name} - {item.membership_number}
<i
style={{ cursor: "pointer" }}
onClick={() => handleDelete(item.id)}
class="float-right fas fa-trash"
></i>{" "}
</p>
);
})}
</div>
)}
</div>
);
}
export default (ShowAllBeneficiariesPage);
I can't completely fix your issue, because I'd need more context and time, but I've found some issues on your code.
Never ever ever, have something in your render code that has a reference to a useRef variable. When a useRef value changes, react will completely ignore it and will not update your component. Use setState for those.
It sounds like your allBeneficiaries instead of being a ref or a state it's just derived state: It looks like it's a derived value from beneficiaries. In this case, you don't need to use any hook, just declare it as a const (e.g. const allBeneficiaries = getBeneficiaries(beneficiaries)). If you have performance issues, then consider using useMemo, but it should not be needed.
Never use a useRef as a dependency value in a useEffect - Same thing, react doesn't care about ref values, so you'll have unexpected behaviour there (effects retriggering when it shouldn't, effects not triggering when they should)
Try to avoid useEffect as much as posible. It should only be used for specific cases, such as fetching something from a server or manipulating the dom. For the rest of them, it's just problematic, best avoided.
Using allBeneficiaries (or any other ref object) as a dependency for a hook won't help you at all. The ref object's identity will never change over the lifetime of a component.
If you want to run an effect/... when the value boxed within the allBeneficiaries ref changes, the dependency will need to be allBeneficiaries.current.
Beside that, there's no good reason to use a ref for allBeneficiaries. Since it affects rendering, you will want to save it as a state atom (useState).

Categories