Reacts js Ant Design multiple input slider handler - javascript

I have multiple elements in the state, and when input slider is dragged i want to set the value into state elements, i've tried to write one function that will setState for the dragged elements in state but it isn't working
Here's what i've tried. When slider changes in the browser it shows -- Cannot read property 'name' of undefined.
Can anyone help to solve this problem. I just want to set slider value into state with one function.
import React, {Component} from "react";
import './table.css';
import { Table, Slider, InputNumber, Row, Col } from 'antd';
export default class TableRender extends Component{
state = {
averageCheck: 0,
newSales: 0,
customerChurn:0,
reSales:0,
totalSales:0,
advertisingBudget: 0,
advertisingAgency: 0,
kpi:0,
salesManager:0,
};
handleChange=(event)=>{
let nam = event.target.name;
let val = event.target.value;
this.setState({[nam]: val});
console.log(nam)
};
render(){
const { averageCheck, newSales, customerChurn } = this.state;
return (
<div className="slider1">
<h2>Tovar</h2>
<p>Tovar o'rtacha qiymati</p>
<Row>
<Col span={12}>
<Slider
name="averageCheck"
min={10000}
max={30000000}
step={5000}
onChange={this.handleChange}
value={typeof averageCheck === 'number' ? averageCheck : 0}
/>
</Col>
<Col span={2}>
<InputNumber
min={10000}
max={30000000}
step={5000}
style={{ margin: '0 16px' }}
value={averageCheck}
onChange={this.handleChange}
/>
</Col>
</Row>
<p>Yangi Sotuvlar</p>
<Row>
<Col span={12}>
<Slider
name="newSales"
min={1000000}
max={30000000}
step={5000}
onChange={this.handleChange}
value={typeof newSales === 'number' ? newSales : 0}
/>
</Col>
<Col span={2}>
<InputNumber
min={1000000}
max={30000000}
step={5000}
style={{ margin: '0 16px' }}
value={newSales}
onChange={this.handleChange}
/>
</Col>
</Row>
<p>Xaridor Kamayishi, %</p>
<Row>
<Col span={12}>
<Slider
name="customerChurn"
min={1}
max={100}
step={1}
marks={marks}
style={{ borderColor: 'green' }}
onChange={this.handleChange}
value={typeof customerChurn === 'number' ? customerChurn : 0}
/>
</Col>
<Col span={2}>
<InputNumber
min={1}
max={100}
step={1}
style={{ margin: '0 16px' }}
value={customerChurn}
onChange={this.handleChange}
/>
</Col>
</Row>
</div>
)
}
}

The antd Slider onChange callback return a value not an event object that's why its give you an error of accessing undefined. Try to modify the onChange callback like this:
<Slider
min={10000}
max={30000000}
step={5000}
onChange={(value) => this.handleChange("averageCheck", value)}
value={typeof averageCheck === "number" ? averageCheck : 0}
/>;
and in your handleChange function:
handleChange = (name, value) => {
let nam = name;
let val = value;
this.setState({ [nam]: val });
console.log(nam);
};
It can be also applied on your InputNumber so you are still using one function

Related

Calling onClick inside map function

I have a custom Input Box and when I type inside a custom input component It'll re-render the typed input inside.
import {
Badge,
Box,
CloseButton,
Grid,
GridItem,
Input,
Text
} from "#chakra-ui/react";
import React, { useEffect, useState } from "react";
function InputTag(props) {
const [tags, setTags] = useState(props.values);
const removeTag = (index) => {
setTags(tags.filter((_, i) => i !== index));
};
const addTag = (event) => {
if (event.target.value !== "") {
setTags([...tags, event.target.value]);
props.setFieldValue("tags", [...tags, event.target.value]);
event.target.value = "";
}
};
useEffect(() => {
props.show === false && setTags([]);
}, [props.show]);
//update values based on click suggestions
useEffect(() => {
setTags([props.values, props.suggTag]);
}, [props.suggTag, props.values]);
return (
<Box
display={"flex"}
border="1px"
borderColor={"gray.200"}
borderRadius={"md"}
padding={2}
>
<Grid templateColumns="repeat(3, 1fr)" gap={2} overflow="visible">
{tags &&
tags.map((tag, index) => (
<GridItem key={index}>
<Badge
variant="solid"
colorScheme={"purple"}
display={"flex"}
borderRadius="full"
justifyContent="space-between"
alignItems="center"
gap={2}
>
<Text>{tag}</Text>
<CloseButton onClick={() => removeTag(index)} />
</Badge>
</GridItem>
))}
</Grid>
<Input
type="text"
name="tags"
id="tags"
variant={"unstyled"}
placeholder="Add Tag"
_placeholder={{ fontsize: "md" }}
onChange={props.handleChange}
onBlur={props.handleBlur}
onError={props.errors}
onKeyUp={(event) =>
event.key === "Enter" ? addTag(event) && event.preventDefault() : null
}
/>
</Box>
);
}
export default InputTag;
Here, when I hit enter It'll render them inside the custom Input Box
I Inserted a custom array of strings as "ex_Tag" inside Previewer.js so that when I click on the word in array, it'll also get rendered inside custom input as well.
function NewUploader({ isOpen, onClose }) {
const cancelRef = useRef();
const ex_tags = ["Design", "Strategy", "Human Centered Design"];
const [show, Setshow] = useState(true);
const [suggTag, setSuggTag] = useState();
const initialValues = {
files: null,
tags: []
};
const validationSchema = yup.object({
files: yup.mixed().required("File is Required"),
tags: yup.mixed().required("tags required")
});
const onSubmit = (values, actions) => {
const formData = new FormData();
formData.append("files", values.files[0]);
formData.append("tags", values.tags);
for (var pair of formData.entries()) {
console.log(pair[0] + ", " + pair[1]);
}
actions.setSubmitting(false);
actions.resetForm();
Setshow(!show);
onClose();
};
const handlethis = (e) => {
e.preventDefault();
};
//insert suggested word to useState so i can pass it to custom input
const handleClick = (tag) => {
setSuggTag(tag);
};
return (
<Modal isOpen={isOpen} onClose={onClose} isCentered>
{/* update code on model here */}
<ModalOverlay />
<ModalContent>
<ModalHeader>
<Text fontWeight={"bold"} color="gray.900">
Upload Buddy
</Text>
</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Flex direction="column" gap={3}>
<Box>
<Text fontWeight={"normal"} color="gray.700">
This learning contentwill not be summarised. to summarize your
content, use{" "}
<Link color={"purple.400"}>Create Knowledge Nugget</Link> option
instead.
</Text>
</Box>
<Box>
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}
>
{(formik) => (
<Form
onSubmit={handlethis}
autoComplete="off"
encType="multipart/form-data"
>
<FormLabel htmlFor="file">
<Text
fontSize="sm"
fontWeight="normal"
color="gray.900"
fontFamily={"body"}
>
Upload files
</Text>
</FormLabel>
{/* drag droop sec */}
{formik.isSubmitting ? (
<>
<Grid
templateColumns="repeat(3, 1fr)"
gap={2}
overflow="hidden"
>
{formik.values.files &&
formik.values.files.map((file, index) => (
<GridItem key={index}>
<Badge
variant="solid"
borderRadius="xl"
colorScheme={"gray"}
w={file.name.length * 4}
h="8"
display="flex"
justifyContent="center"
alignItems="center"
my={2}
>
<Text fontFamily={"body"}>{file.name}</Text>
<CloseButton colorScheme={"blackAlpha"} />
</Badge>
</GridItem>
))}
</Grid>
<Progress colorScheme={"yellow"} isIndeterminate />
</>
) : (
<>
<Dragdrop setFieldValue={formik.setFieldValue} />
<Grid
templateColumns="repeat(3, 1fr)"
gap={2}
overflow="hidden"
>
{formik.values.files &&
formik.values.files.map((file, index) => (
<GridItem key={index}>
<Badge
variant="solid"
borderRadius="xl"
colorScheme={"gray"}
w={file.name.length * 4}
h="8"
display="flex"
justifyContent="space-between"
alignItems="center"
my={2}
>
<Text fontFamily={"body"}>{file.name}</Text>
<CloseButton colorScheme={"blackAlpha"} />
</Badge>
</GridItem>
))}
</Grid>
{formik.errors.files && formik.touched.files && (
<Text fontFamily={"body"} color="red">
{formik.errors.files}
</Text>
)}
</>
)}
<FormErrorMessage>
<ErrorMessage name="file" />
</FormErrorMessage>
<FormLabel htmlFor="tags">
<Text
fontSize="sm"
fontWeight="normal"
color="gray.900"
fontFamily={"body"}
>
Tags
</Text>
</FormLabel>
<InputTag
setFieldValue={formik.setFieldValue}
handleChange={formik.handleChange}
handleBlur={formik.handleBlur.call}
values={formik.values.tags}
show={show}
suggTag={suggTag}
/>
{formik.errors.tags && formik.touched.tags && (
<Text fontFamily={"body"} color="red">
{formik.errors.tags}
</Text>
)}
<FormErrorMessage>
<ErrorMessage name="tags" />
</FormErrorMessage>
<Box
aria-invalid="true"
display={"flex"}
flexDir="row"
gap={2}
my={2}
>
<Text fontFamily={"body"}>Suggested</Text>
<Grid
templateColumns="repeat(3, 1fr)"
gap={2}
overflow="hidden"
>
{ex_tags.map(
(tag, index) => (
<GridItem key={index}>
//I inserted on click call here
<Box onClick={handleClick(tag)}>
<Badge
variant={"subtle"}
borderRadius="lg"
colorScheme={"gray"}
_hover={{
cursor: "pointer",
bgColor: "gray.200"
}}
>
<Text fontFamily={"body"}>{tag}</Text>
</Badge>
</Box>
</GridItem>
),
this
)}
</Grid>
</Box>
<Box display={"flex"} justifyContent="center" my={3}>
<Button
type="button"
ref={cancelRef}
colorScheme="yellow"
isLoading={formik.isSubmitting}
onClick={formik.handleSubmit}
>
<Text
fontWeight="bold"
fontSize="18px"
color="gray.900"
fontFamily={"body"}
>
Submit
</Text>
</Button>
</Box>
</Form>
)}
</Formik>
</Box>
</Flex>
</ModalBody>
</ModalContent>
</Modal>
);
}
export default NewUploader;
but It seems when I render them to the screen it will come out as I triggered the onClick even though I didn't.
For now I commented out the useEffect func inside input component
I have uploaded it to code sandbox Bellow.
https://codesandbox.io/s/amazing-heyrovsky-9kr0ex?file=/src/Previewer.js

How reset value React Material UI Autocomplete using React Hook Forms

I have two autocomplete components in my form where one depends on the other. I want that at a choice of a field in the first component values in the second were reset. I tried a bunch of ways to do it, but nothing worked. Please, tell me how can I solve this problem?
return (
<FormProvider {...methods}>
<form onSubmit={handleSubmit(onSubmitAppealForm)}>
<Grid item container xs={12} sx={{ mt: 2 }} columnSpacing={3}>
<Grid item xs={6}>
<SelectControl
required
control={control}
options={[
{ id: 1, name: "1 - Тематика" },
{ id: 2, name: "2 - Категория" },
{ id: 3, name: "3 - Подкатегория" },
]}
placeholder="Уровень тематики"
label="Уровень тематики *"
name="themeLevel"
readonly
/>
</Grid>
<Grid item xs={6}>
<SelectControl
control={control}
options={getProjectThemesArray() ?? []}
disabled={!themeLevel || themeLevel === 1}
label="Родительская тематика"
defaultValue=""
name="parentThemeId"
loading={isParentThemeFetching}
/>
</Grid>
</Grid>
</form>
</FormProvider>
Autocomplete component:
return (
<>
<Controller
name={name}
control={control}
render={({ field: { value, onChange: handleChange } }) => (
<>
<div className="form-label">{label}</div>
<Autocomplete
onChange={(e, value) => {
handleChange(e, value);
onChange && onChange();
}}
options={options}
noOptionsText="Нет данных"
clearText=""
closeText=""
openText=""
autoHighlight
disabled={loading || disabled}
renderInput={(params) => (
<OutlinedInput
name={name}
{...params.InputProps}
inputProps={{
...params.inputProps,
}}
value={options.length > 1 ? value?.name : ""}
readOnly={readonly}
className={input}
required={required}
placeholder={
defaultValue && disabled
? defaultValue
: placeholder ?? label
}
fullWidth
/>
)}
isOptionEqualToValue={(option, value) => option.id === value.id}
getOptionLabel={(option) => option.name || ""}
renderOption={(props, option) => (
<MenuItem {...props} key={option.id} value={option.id}>
{option.name}
</MenuItem>
)}
popupIcon={
<div className={icon}>
{loading ? <Spinner width={20} height={20} /> : <Arrow />}
</div>
}
/>
</>
)}
/>
</>
I used reset and setField from useForm to my component but it didn't work. Also, resetting the state of the input did not work either.

How to remove the object and update the array using onClick method

I am creating the list from the skidList array and handling copy and delete operation on each skid as well as on click of delete button I am calling deleteSkid method which removes skid at that index and updates the list. However, Instead of deleting skid at a particular index, it deletes the last skid in the array list.
const CreateNewTab = () => {
const [skidList, setSkidList] = useState([]);
const [productNameMap, setproductNameMap] = useState({});
useEffect(() => {
let skidList = [];
let newSkid = {};
newSkid["2"] = "0";
newSkid["3"] = "0";
newSkid["4"] = "0";
skidList.push(newSkid);
setSkidList([...skidList]);
let productNameMap = {};
productNameMap["2"] = "PEN";
productNameMap["3"] = "PENCIL";
productNameMap["4"] = "ERASER";
setproductNameMap({ ...productNameMap });
}, []);
const updateProductQuantity = (skid, key, newQuantity, index) => {
console.log("Inside update Skid Quantity Index= " + index);
skid[key] = newQuantity;
let newSkidList = skidList;
newSkidList.splice(index, 1, skid);
console.log(newSkidList);
setSkidList([...newSkidList]);
};
const deleteSkid = (index) => {
console.log(index);
let newSkidList = skidList;
newSkidList.splice(index, 1);
console.log("Skid deleted from: " + newSkidList);
setSkidList([...newSkidList]);
};
const insertSkid = (skid) => {
setSkidList(skidList.concat([{ ...skid }]));
};
return (
<div>
{skidList.flatMap((skid, index) => (
<div style={{ marginRight: "0", paddingRight: "0" }}>
<Row style={{ margin: "0", padding: "0" }}>
<Col span={19}>
{Object.keys(skid).map((key) => (
<Row>
<Col span={16}>
<h6>{productNameMap[key.toString()]}</h6>
</Col>
<Col span={8}>
<InputNumber
min={0}
defaultValue={skid[key]}
rules={[
{
required: true,
message: "Please input quantity!",
},
]}
onChange={(newQuantity) => {
updateProductQuantity(skid, key, newQuantity, index);
}}
/>
</Col>
</Row>
))}
</Col>
<Col span={5}>
<Row>
<Col span={12}>
<Button
type="primary"
icon={<CopyOutlined />}
size="large"
shape="circle"
onClick={() => insertSkid(skid)}
/>
</Col>
<Col spna={12}>
<Button
type="primary"
size="large"
shape="circle"
danger
icon={<DeleteOutlined />}
onClick={() => deleteSkid(index)}
/>
</Col>
</Row>
}
</Col>
</Row>
<Divider />
</div>
))}
</div>
);
};
It seems it has something to do in how react recycles the dom or something, the item does get deleted from the array but somehow the value is kept in the dom because you're using defaultValue instead value in your inputs, make this little change and it will work
value={skid[key]}
https://codesandbox.io/s/compassionate-ride-1yoti?file=/src/App.js
Your implementation of deleteSkid() is fine,
But you pass the value to the InputNumber as defaultValue so it won't change when the component re-render.
Just replace it with value and it should work.
<InputNumber
min={0}
value={skid[key]}
rules={[
{
required: true,
message: "Please input quantity!"
}
]}
onChange={(newQuantity) => {
updateProductQuantity(skid, key, newQuantity, index);
}}
/>

React component not updating

export class Person extends Component{
constructor(props){
super(props);
this.state = {status:""};
}
componentDidMount(){
/* get status from database */
if (this.props.status === "online"){
document.getElementById("dot").style.background = "green";
this.setState({status:"online"});
}
else if(this.props.status === "offline"){
document.getElementById("dot").style.background = "red";
this.setState({status:"offline"});
}
else if(this.props.status === "away"){
document.getElementById("dot").style.background = "yellow";
this.setState({status:"away"});
}
}
render(){
return(
<ListGroup.Item action variant="success" id="personLi" >
<Row>
<Col>
<Image id="avatar" src={Avatar} roundedCircle />
</Col>
<Col id="profileName">
{this.props.name}
</Col>
<Col>
<span id="dot"></span>
</Col>
</Row>
</ListGroup.Item>
)
}
}
Here is my Person class. I am trying to create a friendbar that has a list of friend names which will get rendered into components that will have a status bar that will change color based on whether they are online (green) and offline (red). However, when I try to create Person components in my friend bar only the first component has a status bar color of green. Currently, I want to just my status to start off as online which is passed into props.
It is not good idea to mixup things. Why you use DOM API together with React?
why do not you want to use the virtual DOM?
And it is an anti-pattern to copy props directly to the component's state.
export class Person extends Component{
constructor(props){
super(props);
this.state = {status:""};
}
componentDidMount(){
fetchState().then((status) => this.setState({status}));
}
getStatusColor() {
switch(this.state.status) {
case "offline": return "red";
case "online": return "green";
case "away": return "yellow";
}
}
render() {
return (
<ListGroup.Item action variant="success" id="personLi" >
<Row>
<Col>
<Image id="avatar" src={Avatar} roundedCircle />
</Col>
<Col id="profileName">
{this.props.name}
</Col>
<Col>
<span style={{backgroundColor: this.getStatusColor()}}></span>
</Col>
</Row>
</ListGroup.Item>
)
}
document.getElementById will get the first instance of that ID on the page and change the style. You could handle this in a more React-y way:
export class Person extends Component{
render(){
let color = 'green';
if(this.props.status === 'offline'){
color = 'red';
} else if (this.props.status === 'away') {
color = 'yellow';
}
return(
<ListGroup.Item action variant="success" id="personLi" >
<Row>
<Col>
<Image id="avatar" src={Avatar} roundedCircle />
</Col>
<Col id="profileName">
{this.props.name}
</Col>
<Col>
<span style={{ backgroundColor: color }} />
</Col>
</Row>
</ListGroup.Item>
);
}
}

React Ref not getting text input field data in form

I am using react Ref in custom input field but it is not getting input content.
I am creating some ref in React class component and using them in form custom input field refs. then i have a button in the form which has "onClick" event to get that data. I am always getting undefined in console when i am getting "ref.current.value"
class LandingAfterSignIn extends React.Component {
titleTextFieldRef = React.createRef();
shortDescriptionMetaTextFieldRef = React.createRef();
longDescriptionMetaTextFieldRef = React.createRef();
imageFieldRef = React.
createRef();
webFieldRef = React.createRef();
contactTextFieldRef = React.createRef();
constructor(props) {
super(props);
// we use this to make the card to appear after the page has been rendered
this.state = {
cardAnimaton: "cardHidden",
isLoading: false,
error: null
};
// super(props);
this.state = {
errors: []
};
}
render() {
let image= require("assets/img/landing-bg.jpg") ;
const { classes, ...rest } = this.props;
//let titleTextFieldRef= this.titleTextFieldRef ;
//let shortDescriptionMetaTextFieldRef = this.shortDescriptionMetaTextFieldRef ;
return (
<div
className={classes.pageHeader}
style={{
backgroundImage: "url(" + image + ")",
backgroundSize: "cover",
backgroundPosition: "top center",
width: "100%"
}}
>
<Header
color="transparent"
routes={dashboardRoutes}
brand="StockNap"
rightLinks={<HeaderLinks />}
fixed
changeColorOnScroll={{
height: 400,
color: "white"
}}
{...rest}
/>
<div>
<div className={classes.container}>
<div className={classes.container}>
<GridContainer>
<GridItem xs={12} sm={12} md={6}>
<h1 className={classes.title}>Welcome {firebase.auth().currentUser.displayName} </h1>
<FirebaseDatabaseMutation type="push" path="user_bookmarks">
{({ runMutation }) => (
<form>
<GridContainer>
<GridItem xs={12} sm={12} md={6}>
<CustomInput
labelText="Company Name/Title"
id="titleTextField"
formControlProps={{
fullWidth: true
}}
inputRef={this.titleTextFieldRef}
>
</CustomInput>
</GridItem>
<GridItem xs={12} sm={12} md={6}>
<CustomInput
labelText="short Description"
id="shortDescription"
formControlProps={{
fullWidth: true,
className: classes.textArea
}}
inputRef={this.shortDescriptionMetaTextFieldRef}
/>
</GridItem>
<GridItem xs={12} sm={12} md={6}>
<CustomInput
labelText="long Description"
id="longDescription"
formControlProps={{
fullWidth: true,
className: classes.textArea
}}
inputProps={{
multiline: true,
rows: 2
}}
inputRef={this.longDescriptionMetaTextFieldRef}
/>
</GridItem>
<GridItem xs={12} sm={12} md={6}>
<CustomInput
labelText="contact"
id="contactTextField"
formControlProps={{
fullWidth: true,
}}
inputRef={this.contactTextFieldRef}
/>
</GridItem>
<Button
style={{
width: 50,
height: 50,
alignSelf: "center",
background: "#039BE5",
color: "white"
}}
variant="fab"
type="submit"
onClick={async ev => {
console.log("submit") ;
ev.preventDefault();
ev.stopPropagation();
ev.nativeEvent.stopImmediatePropagation();
const titleTextField = get(
this.titleTextFieldRef,
"current.value",
""
);
const shortDescriptionMetaTextField = get(
this.shortDescriptionMetaTextFieldRef,
"current.value",
""
);
const longDescriptionkMetaTextField = get(
this.longDescriptionMetaTextFieldRef,
"current.value",
""
);
const contactTextField = get(
this.contactTextFieldRef,
"current.value",
""
);
console.log(this.titleTextFieldRef);
console.log(this.shortDescriptionMetaTextFieldRef);
await runMutation({
titleTextField: titleTextField,
shortDescriptionMetaTextField: shortDescriptionMetaTextField,
created_at: firebase.database.ServerValue.TIMESTAMP,
updated_at: firebase.database.ServerValue.TIMESTAMP
});
set(this.titleTextFieldRef, "current.value", "");
set(this.shortDescriptionMetaTextFieldRef, "current.value", "");
}}
>
+
</Button>
</GridContainer>
</form>
)}
</FirebaseDatabaseMutation>
</GridItem>
</GridContainer>
</div>
</div>
</div>
<div className={classNames(classes.main, classes.mainRaised)}>
<div className={classes.container}>
</div>
</div>
<br/>
<Footer />
</div>
);
}
}
I want to add one more information , customInput are functional components
i want reference from parents to go into that
function CustomInput({ ...props }) {
const {
classes,
formControlProps,
labelText,
id,
labelProps,
inputProps,
error,
white,
inputRootCustomClasses,
success
} = props;
const labelClasses = classNames({
[" " + classes.labelRootError]: error,
[" " + classes.labelRootSuccess]: success && !error
});
const underlineClasses = classNames({
[classes.underlineError]: error,
[classes.underlineSuccess]: success && !error,
[classes.underline]: true,
[classes.whiteUnderline]: white
});
const marginTop = classNames({
[inputRootCustomClasses]: inputRootCustomClasses !== undefined
});
const inputClasses = classNames({
[classes.input]: true,
[classes.whiteInput]: white
});
var formControlClasses;
if (formControlProps !== undefined) {
formControlClasses = classNames(
formControlProps.className,
classes.formControl
);
} else {
formControlClasses = classes.formControl;
}
return (
<FormControl {...formControlProps} className={formControlClasses}>
{labelText !== undefined ? (
<InputLabel
className={classes.labelRoot + " " + labelClasses}
htmlFor={id}
{...labelProps}
>
{labelText}
</InputLabel>
) : null}
<Input
classes={{
input: inputClasses,
root: marginTop,
disabled: classes.disabled,
underline: underlineClasses
}}
id={id}
{...inputProps}
/>
</FormControl>
);
}
From the official docs:
In the typical React dataflow, props are the only way that parent components interact with their children. To modify a child, you re-render it with new props.
Your first inclination may be to use refs to “make things happen” in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to “own” that state is at a higher level in the hierarchy. See the Lifting State Up guide for examples of this.
Currently, you're exactly doing what you should not be doing: using refs to access component methods. That is anti-pattern and make your code suceptible to bugs like you're experiencing right now. You should either:
Lift the state up if you need to pass data from one component to another
Use state container libraries like Redux if you need to trigger actions
In either way I strongly advise you to refactor your code in either direction.

Categories