Material Ui Components props refer each other - javascript

How do I make material UI component property to carry the value of some other property of same component?
Here I want value property to refer checked property.
want to do something like this
<Switch
checked={singleHeading.required}
onChange={onHandleChangeCheck}
name="required"
value={event.target.checked}
/>

Using hooks you can perform that with this:
render() {
const [checked, setChecked] = useState(singleHeading.required);
const handleSwitchCheck = event => {
setChecked(event.target.checked);
onHandleChangeCheck(event);
};
// ... whatever code you have
<Switch
checked={checked}
onChange={handleSwitchCheck}
name="required"
value={checked}
/>
// ... whatever code you have
}

Related

SonarQube "Do not define components during render" with MUI/TS but can't send component as prop

I am getting the following error during sonarqube scan:
Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state. Instead, move this component definition out of the parent component “SectionTab” and pass data as props. If you want to allow component creation in props, set allowAsProps option to true.
I understand that it says that I should send the component as a prop from the parent, but I don't want to send the icon everytime that I want to use this component, is there another way to get this fixed?
import Select from "#mui/material/Select";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faAngleDown } from "#fortawesome/pro-solid-svg-icons/faAngleDown";
const AngleIcon = ({ props }: { props: any }) => {
return (
<FontAwesomeIcon
{...props}
sx={{ marginRight: "10px" }}
icon={faAngleDown}
size="xs"
/>
);
};
const SectionTab = () => {
return (
<Select
id="course_type"
readOnly={true}
IconComponent={(props) => <AngleIcon props={props} />}
variant="standard"
defaultValue="cr"
disableUnderline
/>
);
};
export default SectionTab;
What can you do:
Send the component as the prop:
IconComponent={AngleIcon}
If you need to pass anything to the component on the fly, you can wrap it with useCallback:
const SectionTab = () => {
const IconComponent = useCallback(props => <AngleIcon props={props} />, []);
return (
<Select
id="course_type"
readOnly={true}
IconComponent={IconComponent}
variant="standard"
defaultValue="cr"
disableUnderline
/>
);
};
This would generate a stable component, but it's pretty redundant unless you need to pass anything else, and not via the props. In that case, a new component would be generated every time that external value changes, which would make it unstable again. You can use refs to pass values without generating a new component, but the component's tree won't be re-rendered to reflect the change in the ref.
const SectionTab = () => {
const [value, setValue] = useState(0);
const IconComponent = useCallback(
props => <AngleIcon props={props} value={value} />
, []);
return (
<Select
id="course_type"
readOnly={true}
IconComponent={IconComponent}
variant="standard"
defaultValue="cr"
disableUnderline
/>
);
};

Indeterminate checkbox in react without ref

I am trying to implement a triple-state checkbox to react without using ref method.
I found a lot of solutions with ref.
For example:
const { value, checked, indeterminate } = this.props
return render(
<input
type="checkbox"
value={value}
checked={checked}
ref={el => el && (el.indeterminate = indeterminate)}
/>
)
I need a component implementation with ref method

How can I acess value from textfield in another module in reactJS

I want to have access to the value of a textField in another module in reactjs. The module that wants to have access does not import the whole textfield but only needs access to the value. What is the best way to access the value variable in another module in reactjs?
Here is my functional textField component:
export default function textField(props) {
const [value, setValue] = React.useState("");
const handleChange = (event) => {
setValue(value);
};
return (
<div>
<TextField
id="outlined-multiline-static"
label="Frage"
multiline
onClick={handleClickOpen}
rows={4}
value={value}
placeholder="hello"
variant="outlined"
style={{
backgroundColor: "white",
}}
/>
</div>
);
}
You can send onTextFieldChange function as props whenever textField's value changes you can pass a value to onTextFieldChange function and you can use it in the parent component.
There is an alternate way, Redux
You should try to use redux for the shared state between components which are either not related directly(i.e. sibling components or have a lengthy hierarchy). For small applications, redux is overkilled so should be avoided.
The most likely option that comes to mind here is the concept of lifting state, in which the nearest ancestor component has some means by which it also keeps track of the state, and the passes it into the sibling that needs to track it. You could make this an optional feature of your module by allowing a onChangeCallback prop that is called on each change; this prop could then be passed a setSharedState hook that would set the state on the ancestor:
const ParentComponent = () => {
const [textfieldVal, setTextfieldVal] = useState();
return (
<TextField onChangeCallback={setTextFieldVal} />
);
}
And you update your module to something like:
export default function textField(props) {
const [value, setValue] = React.useState("");
const {onChangeCallback} = props;
const handleChange = (event) => {
setValue(value);
if (typeof onChangeCallback === 'function') {
onChangeCallback(event); // or value, I'm not sure which you should be using here, this might be incorrect
}
};
return (
<div>
<TextField
id="outlined-multiline-static"
label="Frage"
multiline
onClick={handleClickOpen}
rows={4}
value={value}
placeholder="hello"
variant="outlined"
style={{
backgroundColor: "white",
}}
/>
</div>
);
}
This is just a rough example. Other options for passing around state freely would be using Redux or the Context API, but the former might be overkill for this one case and the latter probably not a great fit for a specific, single-use datapoint.
there are may option but the proper option in pass as props
const modle1= () => {
const [textfieldVal, setTextfieldVal] = useState();
return (
<TextField onChangeCallback={setTextFieldVal} />
);
}
export default function textField(props) {
const [value, setValue] = React.useState("");
const {onChangeCallback} = props;
const handleChange = (event) => {
setValue(value);
if (typeof onChangeCallback === 'function') {
onChangeCallback(event); // or value, I'm not sure which you should be using here, this might be incorrect
}
};
return (
<div>
<TextField
id="outlined-multiline-static"
label="Frage"
multiline
onClick={handleClickOpen}
rows={4}
value={value}
placeholder="hello"
variant="outlined"
style={{
backgroundColor: "white",
}}
/>
</div>
);
}
or you can use create context and use context and provide the parent to provide and the child as a consumer but the best option pass as a prop
I would recommend you use the parent-child nature of react in order to handle this. Since I'm not sure the relationship between the other module and this module, I'll provide a rough skeleton.
In a parent component:
export default function ParentComponent(){
const [status, updateStatus] = useState("")
return(
<TextView updateParent={updateStatus}>
</TextView>
)
}
Then in your child component:
const handleChange = (event) => {
setValue(value);
props.updateParent(value);
};
If they are siblings, I would use a parent component and then pass the state down to the sibling. Otherwise, as appropriate, use this parent child relationship to pass and update state.
HTH

Connect Material-ui ToggleButtonGroup to redux-form

I'm trying to connect material-ui ToggleButtonGroup with redux form and getting issues with this.
Here is my code:
<Field
name='operator'
component={FormToggleButtonGroup}
>
<ToggleButton value='equals'>Equal</ToggleButton>
<ToggleButton value='not_equals'>Not equal</ToggleButton>
</Field>
.. and my component, passed to Field:
const FormToggleButtonGroup = (props) => {
const {
input,
meta,
children
} = props;
return (
<ToggleButtonGroup
{...input}
touched={meta.touched.toString()}
>
{children}
</ToggleButtonGroup>
);
};
export default FormToggleButtonGroup;
the problem is, when I select value (toggle option), selected value is not passed to redux store, it passed only after loosing focus and then throws error 'newValue.splice is not a function'
Please help to deal with this issue
Sandbox with sample code
Playing with the component I finally found the solution.
I need manually assign new value got from ToggleButtonGroup component and put this value to redux store. Here is how working code looks:
const FormToggleButtonGroup = (props) => {
const {
input,
meta,
children,
...custom
} = props;
const { value, onChange } = input;
return (
<ToggleButtonGroup
{...custom}
value={value}
onChange={(_, newValue) => {
onChange(newValue);
}}
touched={meta.touched.toString()}
>
{children}
</ToggleButtonGroup>
);
};
Main change is getting redux's function onChange and call it with new value, selected when value toggled. There is onChange related to ToggleButtonGroup component and another onChange related to Redux. You need to call latter when ToggleButtonGroup's onChange occurs.

Redux-form onChange Handler Possibly Overwritten

I created a conditional field which displays yes and no radio buttons. If Yes is selected then the child components should be shown.
The following code accomplishes that. The issue is the selection of yes or no is not registered in the redux state. If I remove the onChange function then the redux state is updated with the Yes or No value, but of course the child components won't show.
I believe the onChange function I pass is overwriting some other onChange function passed by redux-form. Tried many things but had the same result.
I was thinking of just linking the value property with ReactLink, but it's deprecated.
Using React 0.15, Redux-Form 6.0 alpha, and ES7.
const YesNoRadioButtonGroup = (props) =>
<RadioButtonGroup {...props}>
<RadioButton value='Yes' label='Yes' className={s.radio}/>
<RadioButton value='No' label='No' className={s.radio}/>
</RadioButtonGroup>
// TODO: Clear child fields when "No" is selected
// TODO: See if we can generalize into ConditionalField
export class ConditionalRadio extends React.Component {
state = {conditional: false}
updateConditional(event) {
console.log(event)
this.setState({conditional: event.target.value === 'Yes'})
}
render() {
return <div>
<Field name={this.props.name}
component={YesNoRadioButtonGroup}
onChange={::this.updateConditional} /> // The trouble line.
{this.state.conditional ? this.props.children : null}
</div>
}
}
It is used like this:
<ConditionalRadio name='willRelocate'>
<Field name='willRelocateTo.withinCurrentState' component={Checkbox} label='Within Current State'/>
<Field name='willRelocateTo.outOfState' component={Checkbox} label='Out of State'/>
<Field name='willRelocateTo.outOfCountry' component={Checkbox} label='Out of Country'/>
</ConditionalRadio>
If you have defined the field name when creating your redux-form, then you just have to call the default onChange event for that field inside your custom change event handler.
In your case that should be:
updateConditional(event) {
this.setState({conditional: event.target.value === 'Yes'});
this.props.fields.name.onChange(event);
}
Did you try to use the function componentWillReceiveProps in which you can check the new value then set the new conditional? see all helpful React lifecycle functions here
Your Component would be written like this:
export class ConditionalRadio extends React.Component {
state = {conditional: false}
componentWillReceiveProps(nextProps) {
const displayChildren = nextProps.**value of the radio from redux form STORE** === 'Yes'
this.setState({conditional: displayChildren});
}
render() {
return (
<div>
<Field name={this.props.name}
component={YesNoRadioButtonGroup}/>
{this.state.conditional ? this.props.children : null}
</div>
)
}
}
This works well:
class YesNoRadioButtonGroup extends React.Component {
handleChange(event) {
// Call the event supplied by redux-form.
this.props.onChange(event)
// If custom handler exists, call it.
if (this.props.hasOwnProperty('customHandler')) {
this.props.customHandler(event)
}
}
render() {
return <RadioButtonGroup {...this.props} onChange={::this.handleChange}>
<RadioButton value='Yes' label='Yes' className={s.radio}/>
<RadioButton value='No' label='No' className={s.radio}/>
</RadioButtonGroup>
}
}

Categories