0

I need to add form.item to switch button value without using valuePropName="checked". If I used this valuepropName it was difficult to implement my task. In that case, I will comment on it. Then I try to use defaultChecked={this.props.productBenefitDetailsDto.benefitRequired} but it works for one switch button but the other switch button does not support this. Reason is I used checked={this.state.checkedType} and onChange method in switch I think that's the reason. I can use Defaultcheck using without checking but it didn't work for my task. In my code, all values send to the backend and save. no errors in this code. The issue came from when values get back and present in UI one switch button work properly second one not working properly.

I explain my task

I have two switch buttons. The first one is (A) the Second one is B as an example. firstly I want to disable the B switch button already. Then I press the A switch button(value - true) B switch button must be enabled. it was working on my code. Then I click the B switch button (value - true) and I click the A switch button (value - false) In that case B switch button must be (value - false).

This is work in this code but the issue is my form is saved without error but when I get back the data and show the UI A switch button working B switch button not working properly. A button has a blue color and it was "ON" but b switch button was not colored and "ON or "OFF". How to fix this issue I can't find a solution for this.

check the image

My Code

interface Prop {
    productBenefitDetailsDto: ProductBenefitDetailsDto;
    isAuth: boolean
}

interface State {
    checkedType: boolean
    applicableType:boolean
    checkedType:boolean
}
export class BenefitComp extends React.Component<Prop, State> {
    constructor(prop: Prop) {
        super(prop);
        this.state = {
            loading: false,
            dropdownLoading: false,
            checkedType: false,
            applicableType : true,
            checkedType:true
        };
    }

    openCollapse = () => {
        this.setState({openCollapse: !this.state.openCollapse});
    };

    enableButton = (checked: boolean) => {
        if (checked){
            this.props.productBenefitDetailsDto.benefitRequired = true
            console.log("value switch if : ",this.state.checkedType, this.props.productBenefitDetailsDto.benefitRequired)

            this.setState({
                checkedType:false
            })

            // this.setState(prevState => ({
            //     checkedType:!prevState.checkedType
            // }))

        }else {
            this.props.productBenefitDetailsDto.benefitRequired = false
            console.log("value switch else : ", this.state.checkedType,this.props.productBenefitDetailsDto.benefitRequired)
            this.setState({
                checkedType:false
            })
            // this.enableButton2(false)
        }
    };

    enableButton2 = (checked:boolean) => {

        if (checked){
            this.setState({
                checkedType:true
            })
        }else{
            this.setState({
                checkedType:false
            })
        }
    };

    render() {
        return (
            <>
                <Row gutter={[8, 8]}>
                    <Col span={10}>
                    </Col>
                    <Col span={2}>
                        <Form.Item
                            {...this.props.field}
                            name={[this.props.field.name, 'benefitEnabled']}
                            fieldKey={[this.props.field.fieldKey, 'benefitEnabled']}
                            // valuePropName="checked"
                        >
                            <Switch
                                disabled={this.props.isAuth}
                                checkedChildren={<CheckOutlined/>}
                                unCheckedChildren={<CloseOutlined/>}
                                defaultChecked={this.props.productBenefitDetailsDto.benefitEnabled}
                                onChange={this.enableButton}
                            />
                        </Form.Item>
                    </Col>
                    <Col span={2}>
                        <Form.Item
                            {...this.props.field}
                            name={[this.props.field.name, 'benefitRequired']}
                            fieldKey={[this.props.field.fieldKey, 'benefitRequired']}
                            // valuePropName="checked"
                        >
                            <Switch
                                disabled={!this.props.isAuth && this.props.productBenefitDetailsDto.benefitRequired ? false:true}
                                checkedChildren={<CheckOutlined/>}
                                unCheckedChildren={<CloseOutlined/>}
                                checked={this.state.checkedType}
                                // defaultChecked={this.props.productBenefitDetailsDto.benefitRequired}
                                onChange={this.enableButton2}
                            />
                        </Form.Item>
                    </Col>
Dev
  • 13
  • 3

1 Answers1

0

Its a bit confusing IMO to use one switch in uncontrolled mode (with default value) and another in controlled mode (with checked). Its not necessarily wrong, just unusual to mix 2 patterns and hard to reason about. You would benefit from reading about the differences between controlled and uncontrolled components.

But the main problem is you are mutating the props. Specifically this.props.productBenefitDetailsDto.benefitRequired and the other item there. This is explicitly not allowed in react, you can't mutate the props directly with a simple assignment = -- it leads to non-deterministic code execution. If you want to change that data you need to use callbacks to call setstate in the parent where the state lives.

This is why you are seeing a difference in behaviour between when it initially loads data back from the server and when you play around with it before saving. When you mutate the prop incorrectly like this, a rerender is not triggered. Where as when the data comes back, a rerender is triggered. React needs to know every time any state changes so it can rerender, and if it doesnt know, your app will no longer reflect that state. Thats why for every state change, including changing state in the parents it must go through setState.

This problem effectively means before save, your code only looks like its working. The state in memory has been unknowingly changed compared to what react believes that parent state is. When it gets reset back from the server, it suddenly rerenders and the bugs in your implementation become apparant -- as now, even though its not what you want, it is behaving as youve described it in code. In React, this is fatal. Effectively, youve been designing your app against a much larger underlying bug.

You need to refactor entirely such that you never mutate props directly using =, but instead pass the data back up to where that state lives using callbacks and then set that state back into the parent structure. See https://reactjs.org/docs/lifting-state-up.html. As your logic is currently based on false premises, this likely will lead to a rethink in the logic -- which is inevitable.

adsy
  • 8,531
  • 2
  • 20
  • 31
  • Ok I will update the props as you say. I found the issue but I can't fix. Issue is already checkedType: false in state and I use checked={this.state.checkedType} in switch button.Then get back the data and show the UI all switch button false . can you help for this? – Dev Sep 15 '22 at 21:11
  • There is honestly no point in trying to hack the code further to work, or investigate the logic flaw (which is an of itself, a symptom of the larger problem as above). Even if you succeed, its too flawed to put into production and you will just be adding hacks on hacks. You will find after the refactor, you will probably have different problems and might need to post a new question. Sorry, I know this is frustrating! But it's the right way to go. – adsy Sep 15 '22 at 21:13
  • This reason is also as stated -- if you "fixed" how it looks after save, youd simultaneously break it before save with that same fix. You need to first solve the underlying fundamental state issue and then revisit the logic. – adsy Sep 15 '22 at 21:14
  • Thanks for the support I fixed those and I will post another question sorry for my bad English – Dev Sep 15 '22 at 21:20
  • No worries! If you have further problems with the refactor @ me here with the new question :) – adsy Sep 15 '22 at 21:22
  • Thank you I will @ you :D – Dev Sep 15 '22 at 21:25
  • How can set this prop value to state. please any example for this? @Adam Thomas – Dev Sep 15 '22 at 21:29
  • Its worth reading https://reactjs.org/docs/lifting-state-up.html in full – adsy Sep 17 '22 at 03:54