How to Use the Same handleChange Event on Different Components - reactjs

I'm trying to make a function which can disabled textfield when checkbox is checked.
The function is doing what I wanted, but when I trying to make multiple fields with the same function, the components are just bind together.
I've tried to handle them with event.target but I think I messed it up so I deleted the lines.
What should I do so they can separated into two components working individually?
Here's my code:
import React from 'react';
import Checkbox from '#material-ui/core/Checkbox';
import TextField from '#material-ui/core/TextField';
export default function Checkboxes() {
const [required, setRequired] = React.useState(true);
const [checked, setChecked] = React.useState(false);
const [disabled, setDisabled] = React.useState(false);
const handleChange = event => {
setRequired(!required);
setChecked(!checked);
setDisabled(!disabled);
};
return (
<div>
<form>
<TextField
required={required}
autoComplete="off"
id="standard-required"
label="text1"
disabled={disabled}
/>
<Checkbox
label="cb1"
checked={checked}
onChange={handleChange}
color="primary"
/>
</form>
<form>
<TextField
required={required}
autoComplete="off"
id="standard-required"
label="text1"
disabled={disabled}
/>
<Checkbox
label="cb1"
checked={checked}
onChange={handleChange}
color="primary"
/>
</form>
</div>
);
}
Here's my sandbox:
https://stackblitz.com/edit/react-ts-3zvmp5?file=demo.tsx

No need to use state for this purpose. This can be done with manipulating the DOM easily. I have edited your code here in the above link. Just pass the id of the input element to the function and disable it using normal javascript.

I solved my problem by myself.
export default function Checkboxes() {
const [required, setRequired] = React.useState({ setA: true, setB: true });
const [checked, setChecked] = React.useState({ setA: false, setB: false });
const [disabled, setDisabled] = React.useState({ setA: false, setB: false });
return (
<div>
<form>
<TextField
required={required.setA}
autoComplete="off"
id="standard-required"
label="text1"
disabled={disabled.setA}
/>
<Checkbox
label="cb1"
checked={checked.setA}
onChange={() => {
setRequired({ ...required, setA: !required.setA });
setChecked({ ...checked, setA: !checked.setA });
setDisabled({ ...disabled, setA: !disabled.setA });
}}
color="primary"
/>
</form>
<form>
<TextField
required={required.setB}
autoComplete="off"
id="standard-required"
label="text2"
disabled={disabled.setB}
/>
<Checkbox
label="cb2"
checked={checked.setB}
onChange={() => {
setRequired({ ...required, setB: !required.setB });
setChecked({ ...checked, setB: !checked.setB });
setDisabled({ ...disabled, setB: !disabled.setB });
}}
color="primary"
/>
</form>
</div>
);
}
Sandbox here.
However, I decided to separate the hooks.
It's not a large component so I decided to make hooks function individually to avoid any issue might happen in the same hook.
export default function Checkboxes() {
const [requiredA, setRequiredA] = React.useState(true);
const [checkedA, setCheckedA] = React.useState(false);
const [disabledA, setDisabledA] = React.useState(false);
const [requiredB, setRequiredB] = React.useState(true);
const [checkedB, setCheckedB] = React.useState(false);
const [disabledB, setDisabledB] = React.useState(false);
const handleChangeA = () => {
setRequiredA(!requiredA);
setCheckedA(!checkedA);
setDisabledA(!disabledA);
};
const handleChangeB = () => {
setRequiredB(!requiredB);
setCheckedB(!checkedB);
setDisabledB(!disabledB);
};
return (
<div>
<form>
<TextField
required={requiredA}
autoComplete="off"
id="standard-required"
label="text1"
disabled={disabledA}
/>
<Checkbox
label="cb1"
checked={checkedA}
onChange={handleChangeA}
color="primary"
/>
</form>
<form>
<TextField
required={requiredB}
autoComplete="off"
id="standard-required"
label="text2"
disabled={disabledB}
/>
<Checkbox
label="cb2"
checked={checkedB}
onChange={handleChangeB}
color="primary"
/>
</form>
</div>
);
}
sandbox here.

Related

React - pass props into input component

What I need is to be able to customize textAreaCount and other props in each separate instance of <Texarea/>. The textAreaCount is different for each <Texarea/> so how do I modify the component to be able to pass in custom textAreaCount for each <Texarea/>?
https://codesandbox.io/s/rkv88-forked-vjo0rn?file=/src/App.js:0-948
import React, { useState } from "react";
const Textarea = (value, id, maxLength, textAreaLimit) => {
const [textAreaCount, ChangeTextAreaCount] = React.useState(0);
const [state, setstate] = useState({
headline: "",
title: ""
});
const { headline, title } = state;
const changevalue = (e) => {
setstate({
...state,
[e.target.name]: value
});
ChangeTextAreaCount(e.target.value.length);
};
return (
<>
<p>{textAreaCount}/{textAreaLimit}</p>
<textarea
type="text"
rows={5}
id={id}
value={value}
maxLength={maxLength}
onChange={(e) => {
changevalue(e);
}}
/>
</>
);
};
export default function FullWidthTabs() {
return (
<div>
<Textarea value={headline} id="test" maxLength={5} textAreaLimit={5}/>
<Textarea value={title} id="test2" maxLength={10} textAreaLimit={10}/>
</div>
);
}
Forward the props you need.
const Textarea = (props) => {
const [textAreaCount, setTextAreaCount] = React.useState(0);
const recalculate = (e) => {
setTextAreaCount(e.target.value.length);
};
return (
<>
<p>{textAreaCount}/5</p>
<textarea type="text" rows={5} maxLength={5} onChange={recalculate} {...props} />
</>
);
};
Now it will forward any props into the textarea element. This will set the id and will overwrite the rows prop.
<Textarea id="textarea-1" rows={4} />
<Textarea id="textarea-2" rows={5} maxLength={10} />
As we can see you try to pass props as below:
<Textarea value={title} id="test2" maxLength={10} textAreaLimit={10}/>
But In Your Textarea Component you received props argument as multiple args as below:
const Textarea = (value, id, maxLength, textAreaLimit) => {
return (
<>
</>
);
};
Instead that you need to destruct your props argument or you can set whole passed value props as single object props as below:
Method 1:
const Textarea = ({value, id, maxLength, textAreaLimit}) => {
return (
<>
<textarea type="text" id={id} value={value} rows={5} maxLength={maxLength} onChange={recalculate} textAreaLimit={textAreaLimit} />
</>
);
};
Method 2:
const Textarea = ({...props}) => {
return (
<>
<textarea type="text" id={id} value={value} rows={5} maxLength={maxLength} onChange={recalculate} textAreaLimit={textAreaLimit} />
</>
);
};
Method 3:
const Textarea = (props) => {
return (
<>
<textarea type="text" id={props.id} value={props.value} rows={5} maxLength={props.maxLength} onChange={recalculate} textAreaLimit={props.textAreaLimit} />
// Or Instead you can do as below
// <textarea type="text" rows={5} maxLength={5} onChange={recalculate} {...props} />
</>
);
};

Why my checkbox doesn't work in my Dialog?

I create a component for my Dialog and my Checkbox my issue is when my checkbox is not in the Dialog the update works but when it's inside it doesn't work. I don't understand why.
const Popup = ({ title, handleClose, openned, children }) => {
return (
<Dialog className='react-popup-template' fullWidth={true} maxWidth='sm' open={openned} onClose={handleClose} aria-labelledby="parent-modal-title" aria-describedby="parent-modal-description">
<DialogContent id="modal-description" >
<div>
{title && <div><h4 style={{ textAlign: 'center', fontWeight: 'bold', fontSize : '23px' }}>{title}</h4><br/></div>}
{children}
</div>
</DialogContent>
</Dialog>
);
}
const CheckBox = (value, onChange) => {
return (
<label>
<input type='checkbox' value={value} onChange={onChange} />
</label>)
}
const App = () =>{
const [openPopup, setOpenPopup] = React.useState(false)
const [checked, setChecked] = React.useState(false)
const [title, setTitle] = React.useState('')
const [description, setDescription] = React.useState('')
const showModal = (title) =>{
setTitle(title)
setDescription(<CheckBox value={checked} onChange={() => {setChecked(!checked)}} />)
}
return (
<button onClick={() => {showModal('Title')}}>showModal</button>
<PopupTemplate title={title} handleClose={() => { setOpenPopup(false) }} openned={openPopup}>
{description}
</PopupTemplate>)
}
In your Checkbox you should either destructure your props
const CheckBox = ({ value, onChange }) => {
return (
<label>
<input type="checkbox" value={value} onChange={onChange} />
</label>
);
};
Or use your props via the props value
const CheckBox = (props) => {
return (
<label>
<input type="checkbox" value={props.value} onChange={props.onChange} />
</label>
);
};
EDIT:
The state only updates the first time you click the checkbox. Using the callback in the setChecked method will solve this.
...
setDescription(
<CheckBox
value={checked}
onChange={() => {
setChecked((prevChecked) => !prevChecked);
}}
/>
);
...
PS: I don't now if its just a copy/paste error, but you're missing setOpenPopup(true) in your showModal function.
Try this, as mui uses forwarRef for its components this should work,
setDescription(<CheckBox checked={checked} onChange={e => setChecked(!checked)} />)

How to pass state props to another component

I want to pass a state variable to another component but i don't get it what i'm doing wrong.
I have a component for radio inputs and I need to pass that taskLabel to Form component.
path is components/inputs/index.js
const TaskLabel = (props) => {
const [taskLabel, setTaskLabel] = useState('');
return (
<div label={props.taskLabel} >
<input
type='radio'
name='label'
value='urgent'
onChange={(e) => setTaskLabel(e.target.value)}
/>
<input
type='radio'
name='label'
value='not-urgent'
onChange={(e) => setTaskLabel(e.target.value)}
/>
</div>
);
};
i want to receive the taskLabel value, to use it in submitHandler function.
components/form/index.js
const Form = ({taskLabel}) => {
return (
<form onSubmit={submitHandler}>
<input
type='text'
placeholder='Text here'
className='form-input'
value={task}
onChange={(e) => {
setTask(e.target.value);
}}
/>
<TaskLabel taskLabel={taskLabel} />
</form>
)
}
This is what i tried, to pass taskLabel props from label={taskLabel}.
You need to move your state, to Form component, like this:
const [labelProp, setLabelProp] = useState("");
Your TaskLabel component should be
<TaskLabel label={{ labelProp, setLabelProp }} />
That means, you send label, as a prop to TaskLabel component.
In TaskLabel component you need to recive the prosp, by passing to component {label}.
Next, for every input use onChange={(e) => label.setLabelProp(e.target.value)}.
Edited sandbox => https://codesandbox.io/s/laughing-proskuriakova-dhi568?file=/src/components/task-label/index.js
Generally speaking, the concept is "data-down, actions-up". So if you want to pass data down to a lower-level component, you just pass a prop. If you want to update a value from a lower-level component to a higher-level component, you could pass a setter function down as a prop and call that.
Note I just call it taskLevelProp for a little more clarity. You should probably use a better name.
TaskLabel (lower level component)
/* It looks like TaskLabelProp gets passed in from something else.
Otherwise, you would use useState to get your setter function */
const TaskLabel = ({taskLabelProp, setTaskLabelProp}) => {
return (
<div label={props.taskLabel} >
<input
type='radio'
name='label'
value='urgent'
onChange={(e) => setTaskLabelProp(e.target.value)}
/>
<input
type='radio'
name='label'
value='not-urgent'
onChange={(e) => setTaskLabelProp(e.target.value)}
/>
</div>
);
};
Form (higher level component)
const Form = () => {
const [taskLabelProp, setTaskLabelProp] = useState('');
return (
<form onSubmit={submitHandler}>
<input
type='text'
placeholder='Text here'
className='form-input'
value={task}
onChange={(e) => {
setTask(e.target.value);
}}
/>
<TaskLabel taskLabel={taskLabelProp, setTaskLabelProp} />
</form>
)
}
Let me know if this answers your question.
EDIT: Made Form use useState. Based off your code, I was assuming you were using useState at the app level.
function App() {
const [task, setTask] = useState("");
const [taskLabelProp, setTaskLabelProp] = useState("");
const handleChange = (e) => {
setTaskLabelProp(e.target.value);
};
const submitHandler = (e) => {
e.preventDefault();
};
return (
<div className="App">
<form onSubmit={submitHandler}>
<input
type="text"
placeholder="Text here"
className="form-input"
value={task}
onChange={(e) => {
setTask(e.target.value);
}}
/>
<TaskLabel
onChange={handleChange}
taskLabelProp={taskLabelProp}
taskLabel="select"
/>
<button type="submit">fs</button>
</form>
</div>
);
}
export default App;
const TaskLabel = ({ taskLabel, onChange, taskLabelProp }) => {
return (
<div label={taskLabel}>
<input
type="radio"
name="label"
value="urgent"
onChange={(e) => onChange(e)}
checked={taskLabelProp === "urgent"}
/>
urgent
<input
type="radio"
name="label"
value="not-urgent"
onChange={(e) => onChange(e)}
checked={taskLabelProp === "not-urgent"}
/>
not-urgent
</div>
);
};
export default TaskLabel;

How to pass the value of checkbox in react?

God Day, I'm trying to pass a Boolean value of the checkbox using onChange but onChange is already use to toggle the checkbox value. I dont have idea on what will be the other way around. Please guide me Thank you much.
function ExperienceForm() {
const [postData, setPostData] = useState({intern: ''});
const dispatch = useDispatch();
const handleSubmit = (e) => {
e.preventDefault();
dispatch(createPost(postData))
}
const [state, setState] = React.useState({
intern: false,
});
const handleChange = (event) => {
setState({ ...state, [event.target.name]: event.target.checked });
console.log(state.intern);
};
return (
<form autoComplete="off" noValidate className="form" onSubmit={handleSubmit}>
<FormControlLabel control={
<Checkbox
checked={state.intern}
onChange={handleChange ((e) => setPostData({ ...postData, intern: e.target.value }))}
name="intern"
color="primary"
value={state.intern}
/>
}
label="Intern"
/><br/>
<Button className="button" variant="container" color="primary" size="large" type="submit" block>Submit</Button>
</form>
);
}
export default ExperienceForm;
I don't see code of your <FormControlLabel /> and <Checkbox /> components, but with regular html input you can do it like this:
import React, { useState } from "react";
function ExperienceForm() {
const [postData, setPostData] = useState({ intern: false });
const [state, setState] = useState({ intern: false });
const handleChange = ({ target }) => {
setState({ ...state, [target.name]: target.checked });
setPostData({ ...postData, intern: target.checked });
};
return (
<form autoComplete="off" noValidate className="form">
<h2>postData.intern: {postData.intern.toString()}</h2>
<h2>state.intern: {state.intern.toString()}</h2>
<input
type="checkbox"
checked={state.intern}
onChange={handleChange}
name="intern"
color="primary"
value={state.intern}
/>
<button type="submit">Submit</button>
</form>
);
}
export default ExperienceForm;

How to focus text input on transition end?

If the Mui Collapsible has extended I want to show a text input that is focused. The autofocus property does not work. Is there away to achive the focus?
Sandbox
<Collapse in={checked}>
<input autofocus type="text" />
</Collapse>
You can assign a ref to input element and make it focused in the useEffect according to the value of checked.
Sandbox
export default function SimpleCollapse() {
const classes = useStyles();
const [checked, setChecked] = React.useState(false);
const textInput = React.useRef(null);
const handleChange = () => {
setChecked((prev) => !prev);
};
React.useEffect(() => {
if (checked) {
textInput.current.focus();
}
}, [checked]);
return (
<div className={classes.root}>
<FormControlLabel
control={<Switch checked={checked} onChange={handleChange} />}
label="Show"
/>
<div className={classes.container}>
<Collapse in={checked}>
<Paper elevation={4} className={classes.paper}>
<input ref={textInput} type="text" />
</Paper>
</Collapse>
</div>
</div>
);
}

Resources