Disabled Button in React Native - reactjs

I'm in a login problem trying to disable a interaction with a button.
The idea is to disable a submit button when 2 text field are empty, but I have the same result when is empty or not (always clickable, or always not). Below I specify the idea that I have, and how I implement it.
I have two states that stores the values from two text input, then I have a function "isEmpty" that consult if that states are empty (" "). Later, in a button "Submit" I have a property 'disabled' that which value is the result of isEmpty, i.e., if isEmpty is true, disabled is true and the user won't click the button unless the text input are filled. I tried some things, like change the return for another alternatives, or change the value of disable but I don't have good news.
I search from the web and this site, and the solutions doesn't resolve my problem.
Here I detach some code of the function, states and properties.
<View style={styles.submit}>
<TouchableOpacity
onPress={() => checkValidation()}
disabled={emptyFields}
>
<Text style={styles.button}> Submit </Text>
</TouchableOpacity>
</View>
checkEmptyFields -> function call by checkValidation to determinate if the text inputs are empties
const checkEmptyFields = () => {
if (
(id === "" && psw === "") ||
(id === "" && psw !== "") ||
(id !== "" && psw === "")
)
setEmptyFields(true);
};
const checkValidation = () => {
checkEmptyFields();
verifyUser();
resetStates();
};
States used
const [id, setId] = useState("");
const [psw, setPsw] = useState("");
const [emptyFields, setEmptyFields] = useState(false);

I found the problem. In the property disabled, i evaluate a state that ONLY calculates in a onPress function. The fix was to copy the line checkEmptyFields inside the disabled.

Related

Why is my TextInput out of sync with state when I give rapid inputs?

I'm creating a typing race game with React Native which is producing an unexpected bug on Android.
When the user finishes typing a word/spacebar, I set the input state to an empty string.
However, if the user finishes typing a word/spacebar then immediately presses the first letter of the next word/spacebar, the onChangeText event returns the state which existed prior to setting it to a empty string, along with the new letter. It should instead return the new letter by itself.
The bug only occurs when typing very quickly on Android (emulator and real device), IOS hasn't been tested, and the web app works fine typing at any speed.
Snack to try it yourself with complete code: https://snack.expo.dev/#ariato/typing-race-bug-example?platform=android
const Race = () => {
const [input, setInput] = useState("");
const [wordIndex, setWordIndex] = useState(0);
const [letterIndex, setLetterIndex] = useState(0);
const [errorLength, setErrorLength] = useState(0);
const totalIndex = getTotalIndex(wordIndex, letterIndex);
const onChange = (val: string) => {
setInput(val);
checkInput(val);
};
const checkInput = (val: string) => {
const inputLength: number = val.length;
const answer = wordList[wordIndex].substring(0, inputLength);
if (val === answer) {
setErrorLength(0);
if (val === wordList[wordIndex]) {
const isLastWord = wordIndex === wordList.length - 1;
if (isLastWord) {
setWordIndex(0);
} else {
setWordIndex((wordIndex) => wordIndex + 1);
}
setLetterIndex(0);
setInput("");
} else {
setLetterIndex(inputLength);
}
} else {
setErrorLength(inputLength - letterIndex);
}
};
return (
<KeyboardAvoidingView
style={styles.container}
behavior={Platform.OS === "ios" ? "padding" : "height"}
>
<View style={styles.textContainer}>
{wordList.map((word, wordIdx) => (
<Text key={wordIdx}>
{word.split("").map((letter, letterIdx) => (
<Text key={letterIdx} style={getStyles(wordIdx, letterIdx)}>
{letter}
</Text>
))}
</Text>
))}
</View>
<TextInput
value={input}
onChangeText={onChange}
autoCapitalize="none"
autoComplete="off"
autoCorrect={false}
spellCheck={false}
importantForAutofill="no"
autoFocus
keyboardType="visible-password"
style={styles.textInput}
/>
</KeyboardAvoidingView>
);
};
export default Race;
This screenshot is after typing It', and then typing s and a spacebar in rapid succession. The next character to type is underlined. For each incorrect character in the input there is a red letter.
These logs show how the input state is set to an empty string, then becomes It's_ in one key stroke, as though the internal state of the TextInput did not get changed to an empty string.
I tried:
Moving the first setInput() in the onChange() to the if/else statements in checkInput() so that it would only trigger once per event, in case something strange was happening with setState() batching. No change, as expected.

Modal shows previous data

I have a little "bug" here. I have a modal that receives a text, that corresponds a message to show, a state and a property to restore the values of the states when the modal close. In the main, I have three states, each one represents different situations and each show a unique message. The problem occurs when I run the app, choose a date in a datetimepicker, evaluate that in a function, and then I sent that result in a conditional, if "result" is in a determined range -> I set a specific state, else, set another state. Once a state is true, the modal opens with the specific text.
The problem take place when the modal open, the information correspond to a previous "result". I tried to debug with console logs, and I saw that the states doesn't update.
Is it possible that the states take a time to update? Or could be a problem with the cache of the device?
I attach the code below.
Here are the definition of the states
const [modalVisible1, setModalVisible1] = useState(false)
const [modalVisible2, setModalVisible2] = useState(false)
const [modalVisible3, setModalVisible3] = useState(false)
This is the conditional that I explained. picker_value is a variable that take an option from a menu by the user.
const setModal = () => {
(picker_value ===2 && (result>6 && result<150)) ? setModalVisible1(true) : setModalVisible2(true)
if(picker_value == 3)
setModalVisible3(true)
}
And finally, I have this expression (one for each state), to show the modal with the respective message
{modalVisible1 && <MyModal
message={"Test123"}
state={modalVisible1}
restore={resetModal}
/>
}
And I detach the modal
export const MyModal = (props) => {
return (
<Modal visible={props.state}
transparent={true}
animationType='slide'
>
<View style={styles.container}>
<Text>{props.message}</Text>
<TouchableOpacity onPress={() => props.restore()}>
</TouchableOpacity>
</View>
</Modal>
);
EDIT: onChange Method. Date is the current day, and days is a state that saves the result from process_days (calculates the diff between 2 dates)
const [days, setDays] = useState(0)
const onChange = (event, selectedDate) => {
setShow(Platform.OS === 'ios')
setSelectedDay(selectedDate)
setDays(process_days(date, selectedDate))
setPickerValue(formData.pickerValue)
setModal()
}
Reset states
const resetModal = () => {
setModalVisible1(false)
//same for each modal
}

Trying to get Button to copy URL and render snackbar using React Hooks

I'm still learning react hooks. As the title states, when the user hits the button labeled 'Copy to Clipboard' I want it to of course copy the url (which it does), Then I was trying to useEffect so that it will also display a snackbar (from materialui) that tells the user the wesite was copied successfully to the clipboard.
I'm getting the error:
"Expected an assignment or function call and instead saw an expression no-unused-expressions"
I know it's something about how i'm calling "setopenWebsiteSnackbar" in useEffect. I'm sure there's a simple solution i'm just not understanding.
const [isCopiedWebsite, setCopiedWebsite] = useClipboard("https://www.websiteIwanttoCopy.com");
useEffect(() => {setopenWebsiteSnackbar,
console.log("Website Copied")},
[isCopiedWebsite]
)
const [openWebsiteSnackbar, setopenWebsiteSnackbar] = React.useState(false);
const handleClickWebsite = () => {
setopenWebsiteSnackbar(true);
};
const handleCloseWebsite = (event, reason) => {
if (reason === 'clickaway') {
return;
}
setopenWebsiteSnackbar(false);
};
return (
<Button variant="contained" size="large" color="secondary" onClick={setCopiedWebsite}>Copy to Clipboard</Button>
<div className={classes.root}>
<Snackbar open={openWebsiteSnackbar} autoHideDuration={6000} onClose={handleCloseWebsite }>
<Alert onClose={handleCloseWebsite } severity="success">
Website URL successfully copied!
</Alert>
</Snackbar>
)
setopenWebsiteSnackbar is a function. You currently call that function in other places, for example:
setopenWebsiteSnackbar(true);
But in your useEffect you aren't calling it, you just have an unused reference to it:
setopenWebsiteSnackbar,
The comma also doesn't make much sense there. Did you mean to call the function?:
useEffect(() => {
setopenWebsiteSnackbar(true);
console.log("Website Copied");
}, [isCopiedWebsite]);
Basically if you want the "effect" to be that the snackbar opens, then you'd want to call that function and update that state to do that.

How to reset my filter options to their initial blank state? React

I have some input boxes, select drop down, and date picker that are not being reset like I thought they would. Let's start with the input box and select drop down. Here is their code:
<StyledInput
onChange={handleSearchChange}
value={searchText}
placeholder={"Search..."}
/>
<SelectDropDown
isClearable={false}
isSearchable={false}
strict={true}
allowInvalid={false}
getOptionLabel={opt => opt.name}
getOptionValue={opt => opt.value}
value={searchOptions.find(opt => opt.value === searchCol)}
options={searchOptions}
onChange={value => {
handleColSelect(value);
}}
/>
Notice the handleSearchChange and handleColSelect:
const handleColSelect = value => {
setSearchCol(value.value);
};
const handleSearchChange = event => {
setSearchText(event.target.value);
};
I have a button that I want to reset these to their initial states (i.e. get rid of text in the input box, and reset the SelectDropDown).
I've tried doing so:
const clearFilters = () => {
setSearchText(undefined);
setStartDate(undefined);
setEndDate(undefined);
setSearchCol(undefined);
};
And in my button, simply this:
<GreenOutlineButton
onClick={() => {
clearFilters();
}}
>
Clear Filters
</GreenOutlineButton>
There is another part to this to remove the queryParams that are set, and my button does so- however, it does not take away the text or reset the dropdown. Any ideas here?
From the look of it, setSearchText("") should work fine. For the SelectDropDown, you need to add one more entry to the options which will be your default entry. You can do this as follows:
options={[...searchOptions,{label:"Placeholder", value: null}]}
Then, inside clearFilters, use:
setSearchCol(null)
This should give you the desired result. Let me know if this works.

How to undo OnClick function on second click in ReactJS

I have coded a OnClick function that opens a window with a detailed description of the selected object.
However, the window always remains open and to remove it you have to refresh the page. I would like to make sure that at the second click the page returns as before by undoing the function called at the first click.
const setActiveTutorial = (tutorial, index) => {
setCurrentTutorial(tutorial);
setCurrentIndex(index);
};
...
{tutorials &&
tutorials.map((tutorial, index) => (
<TableRow
className={
"list-group-item " + (index === currentIndex ? "active" : "")
}
onClick={() => setActiveTutorial(tutorial, index)}
key={index}
>
<TableCell>{tutorial.title}</TableCell>
<TableCell>{tutorial.size}</TableCell>
<TableCell>{tutorial.country}</TableCell>
...
If you want to use the same function, you can just add a conditional where if currentTutorial already has a value, then it closes the page
const setActiveTutorial = (tutorial, index) => {
if(currentTutorial === tutorial){
setCurrentTutorial(null)
set setCurrentIndex(-1) //or whatever initial value
}
else{
setCurrentTutorial(tutorial);
setCurrentIndex(index);
};
This assumes you can't click on another tutorial while the current one is active.

Resources