react-native-bouncy-checkbox icon indicating copy to clipboard operation
react-native-bouncy-checkbox copied to clipboard

Not toggling after setting disableBuildInState

Open bytesagar opened this issue 3 years ago • 12 comments
trafficstars

So I am using react-hook-form for my getting value

 (
        <BouncyCheckbox
          onPress={(value) => {
            Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
            onChange(value);
          }}
          disableBuiltInState
          ref={(ref: any) => (bouncyCheckboxRef = ref)}
          fillColor={colors.buttonPrimary}
          size={18}
          unfillColor={colors.background}
          style={{ marginTop: 10, marginLeft: 5 }}
          text={label}
          isChecked={value}
          textStyle={{ fontSize: 18, textDecorationLine: "none" }}
          iconStyle={{ borderColor: colors.buttonPrimary, marginRight: -5 }}
          {...props}
        />
      )

When I enable disableBuiltInState button doesnot toggle. And after resetting it with default value checkedState is showing but when clicked again it does not toggle.

bytesagar avatar Apr 04 '22 06:04 bytesagar

Hello @bytesagar Have you checked the manual-state-example ?

Let me check your solution as well

WrathChaos avatar Apr 04 '22 06:04 WrathChaos

@WrathChaos isn't react-hook-form onChange supposed to work for manual state.?

bytesagar avatar Apr 04 '22 06:04 bytesagar

@WrathChaos

export const CustomCheckBoxInput = ({
  control,
  name,
  label,
  ...props
}: CustomChecboxProps) => {
  return (
    <Controller
      control={control}
      defaultValue={false}
      name={name}
      render={({
        field: { value, onChange, onBlur },
        fieldState: { error },
      }) => {
        console.log(value);
        return (
          <BouncyCheckbox
            onPress={(value) => {
              Haptics.notificationAsync(
                Haptics.NotificationFeedbackType.Success
              );
              onChange(value);
            }}
            fillColor={colors.buttonPrimary}
            size={18}
            unfillColor={colors.background}
            style={{ marginTop: 10, marginLeft: 5 }}
            text={label}
            textStyle={{ fontSize: 18, textDecorationLine: "none" }}
            iconStyle={{ borderColor: colors.buttonPrimary, marginRight: -5 }}
          />
        );
      }}
    />
  );
};

this is working as it is supposed to but When I try to set a default value. It doesn't work after some digging found that we have to disable the builtinstate. But now how should I make that work with react-hook-form?

bytesagar avatar Apr 04 '22 06:04 bytesagar

@WrathChaos isn't react-hook-form onChange supposed to work for manual state.?

Honestly, never worked with react-hook-form I need to research about it

WrathChaos avatar Apr 04 '22 07:04 WrathChaos

@WrathChaos having hard time to figure out its usage with react-hook-form. Can you please look into this issue. Would be really helpful.

bytesagar avatar Apr 04 '22 07:04 bytesagar

@WrathChaos everything works fine when I tried using expo-checkbox. Can you make a prop available onChangeValue as in expo-checkbox.

bytesagar avatar Apr 04 '22 07:04 bytesagar

I will take a look this evening @bytesagar

WrathChaos avatar Apr 04 '22 09:04 WrathChaos

@WrathChaos Thank you, will be waiting for your response.

bytesagar avatar Apr 04 '22 09:04 bytesagar

Hello @WrathChaos is there any update on the issue?

bytesagar avatar Apr 05 '22 04:04 bytesagar

same issue, any fix available?

wscld avatar Jul 18 '22 20:07 wscld

Sorry guys, I didn't have time to look at this.

Can someone give me a minimal reproducible example? so it will make it very fast.

WrathChaos avatar Jul 19 '22 06:07 WrathChaos

For those having issues with the checkbox not rendering with disableBuiltInState in react native

You can replace the source content in the file 'node_modules\react-native-bouncy-checkbox\build\dist\BouncyCheckbox.js' with the one provided below, clearly the solution isn't that great but it works for now, give it a try.

Also you will need to handle the isChecked state externally, to restore their states and also handle the state change on onPress.

import * as React from "react";
import { Text, View, Image, Animated, Pressable, } from "react-native";
import styles, { _textStyle } from "./BouncyCheckbox.style";
const defaultCheckImage = require("./check.png");

class BouncyCheckbox extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            initial: true,
            check: false,
            springValue: new Animated.Value(1),
            bounceValue: new Animated.Value(1),
        };
    }

    componentDidMount() {
        if (this.props.isChecked != undefined) {
            this.setState({ checked: this.props.isChecked || false });
        }
    }

    componentDidUpdate(prevprops, prevState) {
        if (this.props.isChecked != undefined && prevState.checked == undefined) {
            this.setState({ checked: this.props.isChecked });
            this.renderCheckIcon();
            this.renderCheckboxText();
        }
    }

    bounceEffect = (value, velocity, bounciness) => {
        const { useNativeDriver = true } = this.props;
        Animated.spring(this.state.bounceValue, {
            toValue: value,
            velocity,
            bounciness,
            useNativeDriver,
        }).start();
    };
    renderCheckIcon = () => {
        const { checked, initial } = this.state;
        const { size = 25, iconStyle, iconComponent, iconImageStyle, fillColor = "#ffc484", ImageComponent = Image, unfillColor = "transparent", disableBuiltInState, isChecked, innerIconStyle, checkIconImageSource = defaultCheckImage } = this.props;
        if (disableBuiltInState && (checked || initial) && isChecked) {
            this.state.initial = false;
            this.state.checked = isChecked;
        } else if (!disableBuiltInState || (!this.state.initial)){
            this.state.checked = checked;
        }

        const statusCheck = this.state.checked;

        return (<Animated.View style={[
                { transform: [{ scale: this.state.bounceValue }] },
                styles.iconContainer(size, statusCheck, fillColor, unfillColor),
                iconStyle,
            ]}>
        <View style={[styles.innerIconContainer(size, fillColor), innerIconStyle]}>
          {iconComponent ||
                (statusCheck && (<ImageComponent source={checkIconImageSource} style={[styles.iconImageStyle, iconImageStyle]}/>))}
        </View>
      </Animated.View>);
    };
    renderCheckboxText = () => {
        const { text, textComponent, textStyle, textContainerStyle, disableText = false } = this.props;
        const { checked } = this.state;
        const checkDisableTextType = typeof disableText === "undefined";
        return ((!disableText || checkDisableTextType) &&
            (textComponent || (<View style={[styles.textContainer, textContainerStyle]}>
          <Text style={[
                    _textStyle(checked),
                    textStyle,
                ]}>
            {text}
          </Text>
        </View>)));
    };
    handleCheck = () => {
        const { checked } = this.state;
            this.setState({ checked: !checked }, () => {
                this.props.onPress && this.props.onPress(this.state.checked);
            });
    };
    render() {
        const { style, bounceEffectIn = 0.9, bounceEffectOut = 1, bounceVelocityIn = 0.1, bounceVelocityOut = 0.4, bouncinessIn = 20, bouncinessOut = 20, TouchableComponent = Pressable } = this.props;
        return (<TouchableComponent {...this.props} style={[styles.container, style]} onPressIn={() => {
                this.bounceEffect(bounceEffectIn, bounceVelocityIn, bouncinessIn);
            }} onPressOut={() => {
                this.bounceEffect(bounceEffectOut, bounceVelocityOut, bouncinessOut);
            }} onPress={() => this.handleCheck()}>
        {this.renderCheckIcon()}
        {this.renderCheckboxText()}
      </TouchableComponent>);
    }
}
export default BouncyCheckbox;
//# sourceMappingURL=BouncyCheckbox.js.map

Cheers

Exhigh avatar Aug 09 '22 22:08 Exhigh

Hello @Exhigh Can you create a PR with this fix? we can make it better together if you don't mind

WrathChaos avatar Nov 11 '22 14:11 WrathChaos

Came here because this issue ate up my entire day as well.

Tried the code segment provided by @Exhigh but was unable to get it to run. Kept getting "Text must be within <Text> component" (points to row 5373 of node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev/js) whenever using disableBuiltInState but the button works as expected when assuming starting state is known at load time.

This package is great but if the value can't be updated via state change call then unfortunately it has needlessly limited use.

** I see your response is typically to ask if I wanted to do manual updates via another button click and I don't. The component should be tied to a state that can be updated whenever the state is updated.

minimal reproducible example:

import BouncyCheckbox from "react-native-bouncy-checkbox";
import React, {Component, useState, useEffect} from 'react';


const AccountSettings = ({nav}) =>{
const [mySetting, setMySetting] = useState(false);

async function updateToggle(){
 setMySetting(true);
}

useEffect(()=>{
updateToggle();
},[]);

return(<BouncyCheckbox
  size={25}
  fillColor="red"
  unfillColor="#FFFFFF"
  text="Does this package work as expected?"
  isChecked={mySetting}
  iconStyle={{ borderColor: "red" }}
  innerIconStyle={{ borderWidth: 2 }}
  textStyle={{ fontFamily: "JosefinSans-Regular" }}
  onPress={(isChecked: boolean) => {}}
/>);
}

EXPECTED OUTCOME: BouncyCheckbox is true / checked ACTUAL OUTCOME: BouncyCheckbox is false / unchecked

*** For anyone else that is hard stuck and NEEDS a quick fix you can:

{mySettings ? <checkbox stuff isChecked={true}> : <></>} {!mySettings ? <checkbox stuff isChecked={false}> : <></>}

is the only method I could get to work.

***** The quick fix posted above doesn't show the animation based on the nature of the state change. Just use a touchable opacity with a background color instead until the state update is fixed.

DaneHoward avatar Jan 19 '23 23:01 DaneHoward

Thank you for providing awesome information @DaneHoward

I will take a look at this tomorrow :)

WrathChaos avatar Jan 21 '23 19:01 WrathChaos

Came here because this issue ate up my entire day as well.

Tried the code segment provided by @Exhigh but was unable to get it to run. Kept getting "Text must be within component" (points to row 5373 of node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev/js) whenever using disableBuiltInState but the button works as expected when assuming starting state is known at load time.

This package is great but if the value can't be updated via state change call then unfortunately it has needlessly limited use.

** I see your response is typically to ask if I wanted to do manual updates via another button click and I don't. The component should be tied to a state that can be updated whenever the state is updated.

Could you try reducing the size of the text, also the react version I am using is version "0.68.2". The error seems to be the fact that the text content cannot seem to render within the text box. Also it seems like you haven't disabledbuiltinstate which sort of is necessary to be able to set your own state and once you do that you will need to change onPressed to change the value of mySetting so that it's value changes rather than isChecked's value.

Exhigh avatar Jan 23 '23 06:01 Exhigh

Hello @Exhigh Can you create a PR with this fix? we can make it better together if you don't mind

The thing is I have moved from working on the project that I was working and well don't necessarily work with react to test any changes. But please do implement the change I suggested but I am not exactly sure how you would convert this code to typescript or just would maintain a separate version for react native in said js form ?

Exhigh avatar Jan 23 '23 06:01 Exhigh

@WrathChaos Any updates on this?

ctriantaf avatar Jan 31 '23 15:01 ctriantaf

Hello @DaneHoward

As far as I understand you want to handle the whole state part on your own. I checked your example and you were not even using the disableBuiltinState prop. @Exhigh is also mention that.

import React from 'react';
import {SafeAreaView, StyleSheet, Text, View} from 'react-native';
import BouncyCheckbox from 'react-native-bouncy-checkbox';
import RNBounceable from '@freakycoder/react-native-bounceable';

const App = () => {
  let bouncyCheckboxRef: BouncyCheckbox | null = null;
  const [checkboxState, setCheckboxState] = React.useState(false);

  return (
    <SafeAreaView
      style={{
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
      }}>
      <View
        style={{
          height: 30,
          width: 150,
          alignItems: 'center',
          justifyContent: 'center',
          borderRadius: 12,
          backgroundColor: checkboxState ? '#34eb83' : '#eb4034',
        }}>
        <Text
          style={{
            color: '#fff',
          }}>{`Check Status: ${checkboxState.toString()}`}</Text>
      </View>
      <BouncyCheckbox
        style={{marginTop: 16}}
        ref={(ref: any) => (bouncyCheckboxRef = ref)}
        isChecked={checkboxState}
        text="Synthetic Checkbox"
        disableBuiltInState
        onPress={(isChecked: boolean = false) =>
          setCheckboxState(!checkboxState)
        }
      />
      <RNBounceable
        style={{
          marginTop: 16,
          height: 50,
          width: '90%',
          backgroundColor: '#ffc484',
          borderRadius: 12,
          alignItems: 'center',
          justifyContent: 'center',
        }}
        onPress={() => {
          console.log(bouncyCheckboxRef?.onPress());
          // bouncyCheckboxRef?.current.onPress();
          // bouncyCheckboxRef?.onPress();
        }}>
        <Text style={{color: '#fff'}}>Synthetic Checkbox Press</Text>
      </RNBounceable>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({});

export default App;

Can you try this example? You can control checkbox state as you wish like this.

WrathChaos avatar Feb 13 '23 14:02 WrathChaos

Hello @Exhigh Can you create a PR with this fix? we can make it better together if you don't mind

The thing is I have moved from working on the project that I was working and well don't necessarily work with react to test any changes. But please do implement the change I suggested but I am not exactly sure how you would convert this code to typescript or just would maintain a separate version for react native in said js form ?

Hey @Exhigh,

To be honest I don't like this approach:

 componentDidUpdate(prevprops, prevState) {
        if (this.props.isChecked != undefined && prevState.checked == undefined) {
            this.setState({ checked: this.props.isChecked });
            this.renderCheckIcon();
            this.renderCheckboxText();
        }
    }

The component itself should re-render the JSX part, we should not re-call them on our own.

Can you provide me with an example of how come it does not re-render itself?

I just cannot reproduce the problem, I need to see it

WrathChaos avatar Feb 13 '23 14:02 WrathChaos

Hello @ctriantaf

Can you take a look at the answers and if you're still having the same problem please provide me a minimal example :)

WrathChaos avatar Feb 13 '23 14:02 WrathChaos

Hi @WrathChaos ,

It seems I had misread the documentation and was waiting for onPress to still pass the state when using disableBuiltinState. I went through the documentation again and it was an easy fix :) Thanks!

image

ctriantaf avatar Feb 20 '23 20:02 ctriantaf

Hi @WrathChaos ,

It seems I had misread the documentation and was waiting for onPress to still pass the state when using disableBuiltinState. I went through the documentation again and it was an easy fix :) Thanks!

image

Love to hear that :) If you need something else please feel free to open an issue :)

WrathChaos avatar Feb 21 '23 09:02 WrathChaos

Since there is no answer for this, I am going to close it. Please feel free to open another issue if there is still a problem :) I am happy to help/resolve the issue

WrathChaos avatar Mar 07 '23 13:03 WrathChaos