I am learning React and I am making a dropdown menu that contains different items. I want to be able to select something from the dropdown menu and then click submit on a button component I have. And then do things based on whatever was in the drop down menu.
class TestDropDown extends React.Component {
state = {selectedOption: null,};
handleChange = selectedOption => {this.setState({ selectedOption });
};
render() {
const { selectedOption } = this.state;
document.write(selectedOption)
return (
<div className="testdropdown">
<Select value={selectedOption} onChange={this.handleChange} options={test_types}/>
</div>);
}
}
This is my dropdown menu component above. Below is my button component.
class ParseButton extends React.Component {
render() {
return (
<div className='parsebutton'>
<Button variant="primary" type='submit'>Submit</Button>{' '}
</div>);
}
}
I am trying to figure out when I click the "Submit" button, how to read whatever was selected in the drop down and then act upon it.
Related
I have a toggle button that show and hides text. When the button is clicked I want it to hide another component and if clicked again it shows it.
I have created a repl here:
https://repl.it/repls/DapperExtrasmallOpposites
I want to keep the original show / hide text but I also want to hide an additional component when the button is clicked.
How to I pass that state or how do I create an if statement / ternary operator to test if it is in show or hide state.
All makes sense in the repl above!
To accomplish this you should take the state a bit higher. It would be possible to propagate the state changes from the toggle component to the parent and then use it in any way, but this would not be the preferred way to go.
If you put the state in the parent component you can use pass it via props to the needed components.
import React from "react";
export default function App() {
// Keep the state at this level and pass it down as needed.
const [isVisible, setIsVisible] = React.useState(false);
const toggleVisibility = () => setIsVisible(!isVisible);
return (
<div className="App">
<Toggle isVisible={isVisible} toggleVisibility={toggleVisibility} />
{isVisible && <NewComponent />}
</div>
);
}
class Toggle extends React.Component {
render() {
return (
<div>
<button onClick={this.props.toggleVisibility}>
{this.props.isVisible ? "Hide details" : "Show details"}
</button>
{this.props.isVisible && (
<div>
<p>
When the button is click I do want this component or text to be
shown - so my question is how do I hide the component
</p>
</div>
)}
</div>
);
}
}
class NewComponent extends React.Component {
render() {
return (
<div>
<p>When the button below (which is in another component) is clicked, I want this component to be hidden - but how do I pass the state to say - this is clicked so hide</p>
</div>
)
}
}
I just looked at your REPL.
You need to have the visibility state in your App component, and then pass down a function to update it to the Toggle component.
Then it would be easy to conditionally render the NewComponent component, like this:
render() {
return (
<div className="App">
{this.state.visibility && <NewComponent />}
<Toggle setVisibility={this.setVisibility.bind(this)} />
</div>
);
}
where the setVisibility function is a function that updates the visibility state.
We have a requirement, where focus needs to be set on dropdown (not the child elements of dropdown) once the Modal is closed.
We are using ReactModal component, it has prop called 'shouldReturnFocusAfterClose'(when set to true) which will set focus back on button (where focus was set before modal opened) once Modal is closed.
<ReactModal
isOpen={isOpen}
shouldCloseOnOverlayClick={shouldCloseOnOverlayClick}
onRequestClose={onRequestClose}
getAppElement={getAppElement}
closeTimeoutMS={200}
contentRef={contentRef}
shouldReturnFocusAfterClose={true} >
</ReactModal>
Above is the code, ReactModal is setting focus as expected (setting focus on button where it was before modal is opened)
*** ReactModal is setting focus as expected (setting focus on button where it was before modal is opened)
*** Once clicked(key event) on the one of the options of dropdown, Modal is opened. Our requirement is...Once it is closed, focus should be set to dropdown button instead of options of dropdown.
okay so lets try using our custom way.
Lets set ref to your select component. And on onRequestClose lets focus on it.
class YourComponent extends React.Component {
refSelect = React.createRef();
openPopup = () => {
this.setState({ isOpen: true });
}
onRequestClose = () => {
this.setState({ isOpen: false });
this.refSelect.focus();
}
render() {
return (
<select ref={ref => this.refSelect = ref} onClick={this.openPopup}>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
</select>
<ReactModal
// your other props...
isOpen={isOpen}
onRequestClose={this.onRequestClose}
shouldReturnFocusAfterClose={false} />
);
}
}
I am trying to implement a collapsible component. I have designed it such as, on click of a button, a block of dynamic text will appear. I made a functional component and using the tags in a class. The name of the component is, CustomAccordion.jsx and using this component in Container.jsx
I have tried to create a button and a function for onClick event.
Part of the CustonAccordion.jsx
const handleToggle = () : string =>{
let content = this.nextElementSibling;
if (content.style.maxHeight){
content.style.maxHeight = null;
}else{
content.style.maxHeight = content.scrollHeight +'px';
}
}
export default function CustomAccordion(props: PropType): React.Component<*> {
const { title, children } = props
return(
<div>
<AccordionButton onClick={() => this.handleToggle()}>{title}</AccordionButton>
<AccordionContent>
<p>{children}
</p>
</AccordionContent>
</div>
)
}
Part of calling Container.jsx
<CustomAccordion title = {this.props.name}>
<p>This is the text passed to component.</p>
</CustomAccordion>
<br />
This does not show the expanded text and it seems that the click event does not work properly. I am very new in react, guessing the syntax might be incorrect.
In react you should generally try to avoid touching DOM directly unless you really have to.
Also you are accessing the handleToggle function wrongly. It should be onClick={() => handleToggle()} because this in your case is window/null and so it has no handleToggle method.
Instead you can use a stateful class component to achieve the same thing.
export default class CustomAccordion extends React.Component {
state = {show: false};
toggle = () => this.setState({show: !this.state.show});
render() {
const {title, children} = this.props;
const {show} = this.state;
return (
<div>
<AccordionButton onClick={this.toggle}>{title}</AccordionButton>
{show && (
<AccordionContent>
<p>{children}</p>
</AccordionContent>
)}
</div>
)
}
}
If you want to have some kind of animation, you can set different className based on the show state instead of adding/removing the elements.
I'm sure this is something trivial but I can't seem to figure out how to access the value of my button when the user clicks the button. When the page loads my list of buttons renders correctly with the unique values. When I click one of the buttons the function fires, however, the value returns undefined. Can someone show me what I'm doing wrong here?
Path: TestPage.jsx
import MyList from '../../components/MyList';
export default class TestPage extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.handleButtonClick = this.handleButtonClick.bind(this);
}
handleButtonClick(event) {
event.preventDefault();
console.log("button click", event.target.value);
}
render() {
return (
<div>
{this.props.lists.map((list) => (
<div key={list._id}>
<MyList
listCollection={list}
handleButtonClick={this.handleButtonClick}
/>
</div>
))}
</div>
);
}
}
Path: MyListComponent
const MyList = (props) => (
<div>
<Button onClick={props.handleButtonClick} value={props.listCollection._id}>{props.listCollection.title}</Button>
</div>
);
event.target.value is for getting values of HTML elements (like the content of an input box), not getting a React component's props. If would be easier if you just passed that value straight in:
handleButtonClick(value) {
console.log(value);
}
<Button onClick={() => props.handleButtonClick(props.listCollection._id)}>
{props.listCollection.title}
</Button>
It seems that you are not using the default button but instead some sort of customized component from another libray named Button.. if its a customezied component it wont work the same as the internatls might contain a button to render but when you are referencing the event you are doing it throug the Button component
I'm building a Modal component. This component takes modal content as children and the button to trigger the modal as a button prop.
This Modal component should render the button. When clicked it has to position a fixed element exactly on top of that button that then animates to a modal dialog. For this the Modal component needs a ref to the button DOM element to measure it's size and position with getBoundingClientRect.
I want the Modal component to be able to receive through button prop both
button DOM element or a custom React element that renders button.
The api of the component looks like this then
const ModalUser = () => (
<div>
<Modal button={<button>Button</button>}/>
<Modal button={<CustomButton>Button</CustomButton>}/>
</div>
)
The render method of Modal looks like this then
class Modal extends React.PureComponent {
render() {
return (
<div>
{React.cloneElement(this.props.button, {
ref: (el) => { this.button = el && el.button ? el.button : el },
onClick: this.onClick,
})}
<span>top: {this.state.top}</span>
<span>left: {this.state.left}</span>
</div>
);
}
}
And thus requires any CustomElement button to expose this.button as a ref to it's containing button.
class CustomButton extends React.PureComponent {
render() {
return (
<button
ref={(el) => { this.button = el }}
onClick={this.props.onClick}
>
<span>Custom</span>
<span>{this.props.children}</span>
</button>
)
}
}
For me this feels not optimal, but it works. I feel like there should be a more elegant solution to this. Does anyone have a suggestion how to do this better.
Here is a working demo
Codepen