onchange event should trigger at the time of onclick event in react - javascript

in that component I need to print onenumber as a text in the textbox in a way like I am selecting one from dropdown and typing number , so at a time we are able to type text in a text box and selecting text from the dropdown ,and in on change function triggered all time like if you type text and select the dropdown as well ,so what should I changed in the on Change event?
import { useState } from "react";
export default function App() {
const [show, setShow] = useState(true);
const [val, setVal] = useState("");
function handleClick(event) {
setVal(event.target.innerHTML);
setShow(false);
}
function handleChange(event) {
setVal(event.target.value);
console.log(event.target.value);
}
return (
<div className="App">
<input
type="text"
value={val}
onChange={handleChange}
onKeyUp={handleClick}
/>
{show && (
<div
style={{
width: "180px",
height: "80px",
background: "pink"
}}
onClick={handleClick}
>
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>
</div>
)}
</div>
);
}

Try this:
import React from 'react'
import { useState } from "react";
function Test() {
const [show, setShow] = useState(true);
const [val, setVal] = useState("");
function handleClick(event, what) {
if (what === 'click') { setVal(event.target.innerHTML) }
setShow(false);
}
function handleChange(event) {
setVal(event.target.value);
}
return (
<div className="App">
<input
type="text"
value={val}
onChange={handleChange}
onKeyUp={(e) => handleClick(e, 'keyup')}
/>
{show && (
<div
style={{
width: "180px",
height: "80px",
background: "pink"
}}
onClick={(e) => handleClick(e, 'click')}
>
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>
</div>
)}
</div>
);
}
export default Test

you can check the condition, That show state is true of false in handleChange and then print number as a text in the textbox

Related

JSX in fuction donot update state

Can anyone give an answer?
Unable to update the state when I click getbtn -> placeRange pass jsx to setbtn ->then unable to update the State when Silde the Range.
import React, { useState } from "react";
export default function Stack() {
const [value, setvalue] = useState(0);
const [btn, setbtn] = useState(<></>);
function placeRange() {
const jsx = (
<>
<input
type="range"
onChange={(e) => {
setvalue(e.target.value);
}}
/>
<h1>{value}</h1>
</>
);
setbtn(jsx);
}
return (
<>
<button onClick={placeRange}>getrange</button>
{btn}
</>
);
}
This seems to be working for me.
Here's a working example at codesandbox
import { useState } from "react";
export default function App() {
const [value, setvalue] = useState(0);
const [btn, setbtn] = useState(<></>);
function placeBtn() {
const jsx = (
<>
<button
onClick={() => {
setvalue(1);
}}
>
Convert to 1
</button>
</>
);
setbtn(jsx);
}
return (
<>
<h1>{value}</h1>
<button onClick={placeBtn}>getbtn</button>
{btn}
</>
);
}
Not sure I fully understand what you are trying to achieve, this is not clear enough for me.
From your code it seems you are trying to set an input range in place when clicking the button, then, you want this range to update the number below it.
If this is the case I suggest the following solution:
import React, { useState } from "react";
export default function Stack() {
const [value, setvalue] = useState(0);
const [showRange, setShowRange] = useState(false);
function placeRange() {
setShowRange(!showRange);
}
return (
<>
<button onClick={placeRange}>getrange</button>
{showRange && (
<>
<input
type="range"
onChange={(e) => {
setvalue(e.target.value);
}}
/>
<h1>{value}</h1>
</>
)}
</>
);
}

How to pass useState amoung the components in react?

I have a register page and Modal component. In register has a useState for visibility of the Modal. I'm passing it as a prop to Modal. When the modal is closed how to change the useState value in the register page.
Register page:
import React, { useState } from 'react'
import {
CCard,
CButton,
CCardBody,
CCardHeader,
CCol,
CForm,
CFormInput,
CFormLabel,
CSpinner,
CRow,
} from '#coreui/react'
import CIcon from '#coreui/icons-react'
import { cilSend } from '#coreui/icons'
import Alert from 'src/components/Alert'
import Modal from 'src/components/Modal'
const FormControl = () => {
const [disabled, setDisabled] = useState(false)
const [visible, setVisible] = useState(false)
const [email, setEmail] = useState('')
const [name, setName] = useState('')
const handleAddMember = async () => {
try {
const data = { email, name }
const _data = await fetch('http://localhost:4000/api/v1/member/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + localStorage.getItem('token'),
},
body: JSON.stringify(data),
})
if (_data.status === 201) {
setVisible(true)
setDisabled(false)
} else if (_data.status === 422) {
setDisabled(false)
} else {
setDisabled(false)
throw new Error()
}
} catch (err) {
setDisabled(false)
}
}
return (
<CRow>
<Modal visible={visible} message="Member added to your community successfully!" />
<CCol xs={6}>
<CCard className="mb-4">
<CCardHeader>
<strong>Add New Member</strong>
</CCardHeader>
<CCardBody>
<p className="text-medium-emphasis small">
Fill in the email address field and name field to add a new member to your community.
</p>
<CForm>
<div className="mb-3">
<CFormLabel>Email address:</CFormLabel>
<CFormInput
type="email"
placeholder="name#example.com"
onChange={(e) => {
setEmail(e.target.value)
}}
/>
</div>
<div className="mb-3">
<CFormLabel>Name:</CFormLabel>
<CFormInput
type="text"
placeholder="Perera's Home"
onChange={(e) => {
setName(e.target.value)
}}
/>
</div>
<div className="mb-3">
<CButton color="primary" disabled={disabled} onClick={() => handleAddMember()}>
{disabled ? (
<CSpinner component="span" className="me-2" size="sm" aria-hidden="true" />
) : (
<CIcon icon={cilSend} className="me-2" />
)}
Submit
</CButton>
</div>
</CForm>
</CCardBody>
</CCard>
</CCol>
</CRow>
)
}
export default FormControl
Modal component:
import React, { useState } from 'react'
import PropTypes from 'prop-types'
import { CButton, CModal, CModalBody, CModalFooter, CModalHeader, CModalTitle } from '#coreui/react'
const Modal = (props) => {
const [visible, setVisible] = useState(props.visible)
return (
<CModal alignment="center" visible={visible} onClose={() => setVisible(false)}>
<CModalHeader>
<CModalTitle>Success!</CModalTitle>
</CModalHeader>
<CModalBody>{props.message}</CModalBody>
<CModalFooter>
<CButton color="primary" onClick={() => setVisible(false)}>
Close
</CButton>
</CModalFooter>
</CModal>
)
}
Modal.propTypes = {
visible: PropTypes.bool,
message: PropTypes.string,
}
export default React.memo(Modal)
You should have just one visible state member, either in the parent component or in the child (Modal), rather than having it in both places.
If you put it in the parent, you can pass it to the child just like any other prop:
return <Modal visible={visible} setVisible={setVisible}>{/*...*/}</Modal>
Modal's code can then call props.setVisible with the appropriate flag.
If you only want Modal to be able to hide itself (not show itself), you might instead pass a wrapper function that calls setVisible(false):
const hide = useCallback(() => setVisible(false), [setVisible]);
// Optional, see below −−−−−−−−−−−−−^^^^^^^^^^
// ...
return <Modal visible={visible} hide={hide}>{/*...*/}</Modal>
...and then Modal's code calls hide() to hide the modal.
(Making setVisible a dependency in the useCallback call is optional; state setter functions are stable; they don't change during the lifetime of the component. Some linters aren't quite smart enough to realize that and may nag you if you don't include it, but most are smarter than that.)
Here's a highly simplified example:
const {useState} = React;
const Example = () => {
const [visible, setVisible] = useState(false);
return <div>
<input type="button" value="Open" disabled={visible} onClick={() => setVisible(true)} />
<Modal visible={visible} setVisible={setVisible} />
</div>;
};
const Modal = (props) => {
if (!props.visible) {
return null;
}
return <div className="modal">
<div>This is the modal</div>
<input type="button" value="Close" onClick={() => props.setVisible(false)} />
</div>;
};
ReactDOM.render(<Example />, document.getElementById("root"));
.modal {
border: 1px solid grey;
padding: 4px;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
Or with destructuring (I generally use destructuring with props, but it didn't look like you were):
const {useState} = React;
const Example = () => {
const [visible, setVisible] = useState(false);
return <div>
<input type="button" value="Open" disabled={visible} onClick={() => setVisible(true)} />
<Modal visible={visible} setVisible={setVisible} />
</div>;
};
const Modal = ({visible, setVisible}) => {
if (!visible) {
return null;
}
return <div className="modal">
<div>This is the modal</div>
<input type="button" value="Close" onClick={() => setVisible(false)} />
</div>;
};
ReactDOM.render(<Example />, document.getElementById("root"));
.modal {
border: 1px solid grey;
padding: 4px;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
you can pass the setVisible as well in the modal component and then use the same setState on both component
<Modal visible={visible} setVisible={setVisible} message="Member added to your community successfully!" />
use this like
props.visible
props.setVisible

How to properly control focus and blur events on a React-Bootstrap InputGroup?

I have a single input element from react-bootstrap that will allow the user to change the field value and 2 buttons will appear, one to accept the changes and the other will cancel the changes leaving the original value in.
I manage to control the focus and blur events by delegating the listeners to the wrapping component, my thinking is that since the focus is still within the wrapping component, I won't lose its focus, but pressing the inner buttons seems to blur the focus, therefore the Accept and Cancel buttons don't fire any events...
Here is my code example:
import { useState, useEffect, useRef } from "react";
import { InputGroup, Button, FormControl } from "react-bootstrap";
import "./styles.css";
const InputField = ({ title }) => {
const formRef = useRef(null);
const [value, setValue] = useState(title);
const [toggleButtons, setToggleButtons] = useState(false);
const onChange = (e) => {
setValue(e.target.value);
};
const onFocus = () => {
setToggleButtons(true);
};
const onBlur = () => {
setToggleButtons(false);
};
const acceptChange = () => {
console.log("Accept");
setToggleButtons(false);
};
const cancelChange = () => {
console.log("Cancel");
setToggleButtons(false);
};
useEffect(() => {
const form = formRef.current;
form.addEventListener("focus", onFocus);
form.addEventListener("blur", onBlur);
return () => {
form.removeEventListener("focus", onFocus);
form.removeEventListener("blur", onBlur);
};
}, []);
return (
<div className="App">
<InputGroup className="m-3" style={{ width: "400px" }}>
<FormControl
ref={formRef}
value={value}
onChange={onChange}
// onFocus={onFocus}
// onBlur={onBlur}
/>
{toggleButtons ? (
<InputGroup.Append>
<Button variant="outline-secondary" onClick={() => acceptChange()}>
Accept
</Button>
<Button variant="outline-secondary" onClick={() => cancelChange()}>
Cancel
</Button>
</InputGroup.Append>
) : null}
</InputGroup>
</div>
);
};
export default function App() {
return (
<>
<InputField title={"Input 1"} />
<InputField title={"Input 2"} />
<InputField title={"Input 3"} />
<InputField title={"Input 4"} />
</>
);
}
A couple of changes are needed to make this work:
The toggle buttons need to always be in the DOM, so hide them rather than only rendering if the focus is there.
To avoid hiding the buttons when the blur occurs from the input to one of the buttons you can check if the newly focused element is a sibling of the input by using the event's relatedTarget and the currentTarget.parentNode.
For example:
import { useState } from "react";
import { InputGroup, Button, FormControl } from "react-bootstrap";
import "./styles.css";
const InputField = ({ title }) => {
const [value, setValue] = useState(title);
const [toggleButtons, setToggleButtons] = useState(false);
const onChange = (e) => {
setValue(e.target.value);
};
const onFocus = () => {
setToggleButtons(true);
};
const onBlur = (e) => {
if (!e.currentTarget.parentNode.contains(e.relatedTarget)) {
setToggleButtons(false);
}
};
const acceptChange = () => {
console.log("Accept");
setToggleButtons(false);
};
const cancelChange = () => {
console.log("Cancel");
setToggleButtons(false);
};
return (
<div className="App">
<InputGroup className="m-3" style={{ width: "400px" }}>
<FormControl
value={value}
onChange={onChange}
onFocus={onFocus}
onBlur={onBlur}
/>
<InputGroup.Append className={toggleButtons ? "d-flex" : "d-none"}>
<Button
onBlur={onBlur}
variant="outline-secondary"
onClick={() => acceptChange()}
>
Accept
</Button>
<Button
onBlur={onBlur}
variant="outline-secondary"
onClick={() => cancelChange()}
>
Cancel
</Button>
</InputGroup.Append>
</InputGroup>
</div>
);
};
export default function App() {
return (
<>
<InputField title={"Input 1"} />
<InputField title={"Input 2"} />
<InputField title={"Input 3"} />
<InputField title={"Input 4"} />
</>
);
}
https://codesandbox.io/s/input-group-focus-slwoh

onClick detection for both an li and button nested within li

so i'm trying to implement the line-through feature while having a delete button. clicking on the li text crosses out the item, and clicking on the del button removes it.
functionally, it works. the issue is when I delete an itme, say "2", it will apply the line-through style to the list item below it. i'm guessing this is because "onClick" is detected twice - both inside the list item and the button (because the button is technically nested within the list item). the moment I press on the DEL button for 2, the onClick is detected for list item 3, applying the line-through style. what would be the best way to go about correcting this?
my code with an App component and ListItem component:
import React, { useState } from "react";
import ListItem from "./ListItem";
function App() {
const [inputText, setInputText] = useState("");
const [items, setItems] = useState([]);
function handleChange(event) {
const newValue = event.target.value;
setInputText(newValue);
}
function addItem() {
setItems((prevItems) => {
return [...prevItems, inputText];
});
setInputText("");
}
function deleteItem(id) {
setItems((prevItems) => {
return prevItems.filter((item, index) => {
return index !== id;
});
});
}
return (
<div className="container">
<div className="heading">
<h1>To-Do List</h1>
</div>
<div className="form">
<input onChange={handleChange} type="text" value={inputText} />
<button onClick={addItem}>
<span>Add</span>
</button>
</div>
<div>
<ul>
{items.map((todoItem, index) => (
<ListItem
key={index}
id={index}
item={todoItem}
delete={deleteItem}
/>
))}
</ul>
</div>
</div>
);
}
export default App;
____________________________________________________________________________________________________
import React, { useState } from "react";
function ListItem(props) {
const [clickedOn, setClickedOn] = useState(false);
function handleClick() {
setClickedOn((prevValue) => {
return !prevValue;
});
}
return (
<div>
<li
onClick={handleClick}
style={{ textDecoration: clickedOn ? "line-through" : "none" }}
>
{props.item}
<button
onClick={() => {
props.delete(props.id);
}}
style={{ float: "right" }}
>
<span>Del</span>
</button>
</li>
</div>
);
}
export default ListItem;
As you already wrote, user events are propagated up the DOM tree. To stop the propagation, you can use event.stopPropagation() ref in your event handler
<button
onClick={(event) => {
event.stopPropagation();
props.delete(props.id);
}}
style={{ float: "right" }}
>

Enable-Disable button with ReactJS

I am trying to enable or disable a button based on whether or not there is text in my input but cant seem to achieve it. When I manually set {true OR false} in the disabled property of Button function it works fine but I am really confused on how to set that dynamically based on the content of the input.
Any guidance is super welcome!
This is my app code
import { useState } from "react";
function Input (props){
const { onChange, value } = props
return (<input value={value} onChange={onChange} type="text" placeholder="Add a ToDo" maxLength="50"/>)
}
function Button (props) {
const {onChange, state, text} = props
return (<button disabled={false} onChange={onChange}>{text}</button>)
}
function App() {
const [text, setText] = useState("");
const [state, setSate] = useState(true);
const handleChange = (event) => {
if (!setText(event.target.value)) {
setSate(false);
} else {
setSate(true);
}
};
return (
<div className="App">
<div className="container">
<Input value={text} onChange={handleChange} />
<Button onChange={() => handleChange(state)} text="Add" />
<Button onChange={() => handleChange(state)} text="Clean" />
</div>
);
}
export default App;
Button element should change to:
function Button (props) {
const {disabled, onChange, state, text} = props
return (<button disabled={disabled} onChange={onChange}>{text}</button>)
}
Rendering of it should change to:
...
<Button disabled={!text} onChange={() => handleBtn()} text="Add" />
...
Sandbox: https://codesandbox.io/s/zen-hawking-qqzkw?file=/src/App.js
The idea is to send down disabled prop which would be true if the there is no text in the field.
ALSO, handleChange should look like this:
const handleChange = (event) => {
setText(event.target.value);
};
because the rest of your code in that function does not do anything.
Buttons should have their own handler functions .e.g. const handleBtn = () => {};
So you should pass the state value you are using to store whatever the users write in the input to the button so that the button knows when the input has text on it or not. And then your second state value can be used to store your todo list, so something like this
import { useState } from "react";
function Input({ handleChange, value }) {
return (
<input
value={value}
onChange={handleChange}
type="text"
placeholder="Add a Todo"
maxLength="50"
/>
);
}
function Button({ handleClick, text, disabled }) {
return (
<button disabled={disabled} onClick={handleClick}>
{text}
</button>
);
}
function App() {
const [value, setValue] = useState("");
const [todoList, setTodoList] = useState([]);
const handleChange = (event) => {
setValue(event.target.value);
};
const handleAdd = () => {
setTodoList([...todoList, value]);
handleClear();
};
const handleClear = () => {
setValue("");
};
return (
<div className="App">
<div className="container">
<Input value={value} handleChange={handleChange} />
<Button handleClick={handleAdd} disabled={!value} text="Add" />
<Button handleClick={handleClear} disabled={!value} text="Clear" />
</div>
</div>
);
}
export default App;

Categories

Resources