I'm trying to create a radiobutton component, and it's causing me some headaches.
This is my code:
class RadioButton extends React.PureComponent {
constructor(props) {
super(props);
this.state = { selected: '' };
}
handleRadioButtonChange = event =>
this.setState({ selected: event.target.value });
render() {
const { disabled, label, name, value } = this.props;
const { selected } = this.state;
return (
<StyledLabel>
<RadioButtonComponent
id={value}
name={name}
value={value}
checked={selected === value}
disabled={disabled}
onChange={this.handleRadioButtonChange}
/>
<span>{label}</span>
</StyledLabel>
);
}
}
RadioButtonComponent is something I use to style the radiobutton the way I want.
const RadioButtonComponent = ({ checked, ...props }) => (
<RadioButtonContainer>
<HiddenRadioButton checked={checked} {...props} />
<StyledRadioButton checked={checked}>
<Icon viewBox="0 0 24 24">
<circle />
</Icon>
</StyledRadioButton>
</RadioButtonContainer>
);
The HiddenRadioButton is the input with style "radio" and it's hidden with the hideVisually function from the polished library. The StyledRadioButton is a styled components div that is styled to make it look the way I want.
It works to the level that they are displayed, can be clicked and they toggle on. Obviously they can't be toggled off. But when I create say 2 checkboxes with the same name:
<RadioButton value="1" name="group" />
<RadioButton value="2" name="group" />
I can select both. I would expect one to switch off and the other on.
When I change RadioButtonComponent to input type="radio" it works, but doesn't look the way I want. Also, it seems like I have to click it twice to select it.
Any ideas what might be wrong?
EDIT:
If I unhide the html checkbox, it does toggle. But StyledRadioButton doesn't get the right 'checked' state?
Codesandbox: https://codesandbox.io/s/j5zorwr3v
I'm not sure I understand why you have four components in order to achieve this, but I see one area causing unnecessary complication - you are trying to implement radio buttons as individual components, when actually radio buttons are more akin to select drop down menus. You would have multiple values, but only one is "selected", and only one value is stored in state.
You could break out each radio to it's own component, but then you'd have to manage selected state across multiple components, and I believe this is where you could optimize your code. See this Code Sandbox:
https://codesandbox.io/s/9jjwwzwoxw
This is the simplest working example I could come up with. Note that we provide the various values to the single component, then map over the values to create each radio button.
Also note that you can apply your style customizations to a component within the map, which is different than trying to manage selected state across multiple radio components.
Edit: I've added an example of how to add a className and CSS styling within each radio to determine which elements is checked.
Related
Currently I have a Createable component that has a dropdown menu and users can also freely enter any new value. However I want to disable creating new values if the maximum number is reached.
Here I used a custom menulist component to hide the dropdown (There is still a visible small line here beneath the component tho). But the user can still type, in the input. Is there any way to disable this specifically and not disable the whole component since they should still be able to delete selections.
const CustomMenuList = (props: any) => value?.length === 5 ? null : <components.MenuList {...props} />;
Your logic is generally correct but you need to apply it to the Menu component which is the container for MenuList, that's why you still see something when you hide MenuList
import { components } from 'react-select';
const CustomMenu = ({ children, ...props }) =>
props.options.length === 5 ? null : (
<components.Menu {...props}>{children}</components.Menu>
);
<Select
components={{
Menu: CustomMenu,
}}
/>
As for disabling the input, just follow the same logic and override the input's disabled attribute when options reach 5.
I am trying to add an indeterminate state to row checkboxes based on selection status of other checkboxes inside a detail panel. To do this I am creating a custom checkbox component and doing some logic to see if indeterminate should be true, the only problem is the checkbox needs access to the row id it is associated with to do that check. Thus far I've found nothing to pass anything other than the given CheckboxProps given by MUI, which contains no row information. There is something called componentsProps where I can pass other props to a component, but I've yet to find a way to pass the particular row id to its associated checkbox. Does anyone know of a solution to this?
.
.
.
const customCheckbox = (props: CheckboxProps) => {
return <Checkbox {...props} indeterminate={someArray.includes(theRowIdThisCheckboxIsUsedIn)} />
};
<DataGridPro
{...data}
components={{
BaseCheckbox: customCheckbox,
}}
/>
hi when you use custom checkbox component you cant use onSelectionModelChange to give you rows id you must write their logic too
I have a input type radio
const AnswerOptions = (props) => (
<>
<input
type="radio"
id="something"
name="something"
value={props.option}
onClick={e => save(e)}
></input>
<label htmlFor="something">
<h1>{props.option}</h1>
</label>
</>
)
export default AnswerOptions
Then I am looping through an array and calling AnswerOptions for every item in the array;
import AnswerOptions from './AnswerOptions';
const [page, setPage] = useState(1);
const result = product[page].map((item) => {
return (
<AnswerOptions
key={index}
preset={preset}
setSelected={setSelected}
option={option}
description={description}
/>
)
})
Then I am rendering the components.
<>
{result}
</>
I am doing this for multiple pages by changing the page variable and selecting the corresponding sub array.
The problem is the checkbox which is selected on the first page changes selection state of radio button of all the pages.So every page has same selected option.For example if I select second radio button from the top then all the pages are set on the second radio button as well. Selecting other option results the same. I need a way to control the radio check's initial and consequent states.
Setting defaultChecked and checked attributes did not work.
#peter gave the correct answer in the comments. The issue was with key that I was providing to the component. Every page has an index of 0,1,2,3 and likewise. Which meant when I gave some data to index 1 of page 1, every other index 1 receives the same data. using uuid for keys solved this problem by providing unique identifiers for each <AnswerOptions /> component.
We are supposed to use unique keys instead of an index anyways.
I have a fancy UI in which have a few 'panes' with dividers in between that let you change what each one does. Say I have two different components - a to-do list and a simple text editor. I want you to be able to change the component present in each pane to make a flexible UI. For example, I might want to change the pane on the left from a text editor to a to-do list. Assuming I have a parent element Pane, how could I replace one of its children with another?
<Pane>
<TextEditor /> /* I want to replace that with a <ToDoList /> when I press a button */
<SomeOtherComponentOnTheRight />
</Pane>
I've tried storing React.Children.toArray(this.props.children) in the <Pane />'s state (as this.state.currentChildren), and replacing the element there, but for some reason I can't find a way to get the index of <TextEditor /> in the <Pane />'s this.state.currentChildren because for some reason this.props.children does not preserve children's props, and so I can't transmit data through it.
Sorry if I've overcomplicated this, but I simply want to know how to change a component's children dynamically.
You could check the state in your JSX to change what is displayed such as:
<Pane>
{ this.state.showEditor ? <TextEditor/> : <ToDoList /> }
<SomeOtherComponentOnTheRight />
</Pane>
Elsewhere in your code you would have some button that invokes an onClick event handler that would set the state of 'showEditor' to true/false depending on the previous state.
You can store the selected components in an array or object, then assign the selected component to a variable (just make sure it starts with an uppercase letter) and then use it as a component:
const routes = {
a: TextEditor,
b: ToDoList
};
const ChosenComponent = routes['a']; // select your component and store in variable
return (
<Pane>
<ChosenComponent />
<SomeOtherComponentOnTheRight /> {/* render selected variable as component */}
</Pane>
);
I'm learning to Think in React, but don't understand why the SearchBar in the example needs to have value={this.props.filterText} and checked={this.props.inStockOnly}, the jsFiddle still works without them and it doesn't make sense for props to be passed to the SearchBar as the Search is the one handling user input and making changes to the state. The user input will be reflected in the value of the input without it being set to this.props.filterText so why is it there?
var SearchBar = React.createClass({
handleChange: function() {
this.props.onUserInput(
this.refs.filterTextInput.value,
this.refs.inStockOnlyInput.checked
);
},
render: function() {
return (
<form>
<input
type="text"
placeholder="Search..."
value={this.props.filterText}
ref="filterTextInput"
onChange={this.handleChange}
/>
<p>
<input
type="checkbox"
checked={this.props.inStockOnly}
ref="inStockOnlyInput"
onChange={this.handleChange}
/>
{' '}
Only show products in stock
</p>
</form>
);
}
});
React has concept of controlled components. A controlled component means its value is set by state (And not the other way around i.e. State being set by value of component).
Consider the following example:
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = {term : ''};
}
render() {
return (
<div>
<input value={this.state.term} onChange = {event => this.setState({term : event.target.value}) }/>
</div>
);
}
}
In above example <SearchBar /> is a Controlled Component.
Following will be sequence of events:
You type 'abc' in input field.
At this time value of input field does not change. Rather the State of component is changing because of our code in onChange Event.
As the state of component changes, the component is rendered again. And now the value of component becomes 'abc'.
This concept becomes more important when we use redux, Actions etc.
Because you will be needing the inputted value from the search bar to the upper component. For instance, if you need to filter a collection based on the given value (through search bar), then the filtering will happen on the upper component, not on the search bar. Search bar is only for the input. We put the value of the search bar from the props to make sure that the values are aligned.
The example here depicts the use of controlled input from the parent component. As you see
<input
type="text"
placeholder="Search..."
value={this.props.filterText}
ref="filterTextInput"
onChange={this.handleChange}
/>
Here the value of input box is set to {this.props.value} and in the handlechange function you are the onUserInput function which you check is again passed as a prop to the Searchbar. This calls the handleUserInput function ni the FilterableProductTable component and it sets the states filterText, inStockOnly and only these are passed as props to the Searchbar component. So although you can do without it, but controlled input is the way to go in most cases since we are accepting the value provided by the user and updating the value prop of the <input> component. This pattern makes it easy to implement interfaces that respond to or validate user interactions. i.e. if you want to validate an input field or put restrictions on the input value its easier to do with controlled input