React Native no models show - reactjs

I would like to show modal when the user enabled the switch or disabled. what should i do to achieved what i want? this is my current code. I am new in this technology, I hope you all understand , Please bear with me. thanks
import {SimpleModal} from '../../components/modal/Modal';
const [isModalVisible, setisModalVisible] = useState(false);
const changeModalVisible=(bool) =>{
setisModalVisible(bool);
}
const confirmDelete = (id,status) =>{
console.log("changeModalVisible: ",changeModalVisible(true))
if (status == 0){
if (changeModalVisible(false)) {
handleDelete(id,status);
} else {
alert("error")
}
}else{
if (changeModalVisible(true)) {
handleActivate(id,status);
} else {
}
}
}
<FlatList
keyExtractor={(item, index) =>index.toString()}
data={documentlists}
renderItem={({ item }) => (
<DocumentLocation
key={item.name}
status={item.status}
editHandler={handleEdit}
pressHandler={confirmDelete}
/>
)}
/>
<Modal
transparent={true}
animationType='fade'
visible={isModalVisible}
nRequestClose={() => changeModalVisible(false)}
></Modal>
<SimpleModal/>
component/model/Model.js
const SimpleModal = () => {
return (
<TouchableOpacity
disabled={true}
style={formStyles.container}
>
<View>
<View>
<Text>
Sample modal header
</Text>
<Text>
Sample modal description
</Text>
</View>
</View>
</TouchableOpacity>
)
}
work flow, if the client switch the toggle popup modal will appear,
in the modal, i want two button that is ok and cancel, if the user click the ok, the data will updated and if cancel, no updated data, note the functionality of updating data is already working, my problem is the modal , please refer to this image

As per your comment this is the flow you expect.
User clicks switch in flatlist
If the value is false the status is updated
If value is true, a confirmation Modal is shown.
There are some changes required
renderItem={({ item,index }) => (
<DocumentLocation
key={item.name}
status={item.status}
editHandler={handleEdit}
pressHandler={(value)=>confirmDelete(value,index)}
/>
)}
Here the value should come from the switch
instead of using the showModalVisible have a state to manage the selectedIndex
const [selectedIndex, setSelectedIndex] = useState(-1);
If an item is changed to true we set the selectedIndex
We use that to control the visibility of the modal
<Modal visible={selectedIndex > -1} onRequestClose={() => setSelectedIndex(-1)}>
<Text>Approve?</Text>
<Button
title="Yes"
onPress={() => {
updateSelectedItem(selectedIndex, true);
setSelectedIndex(-1);
}}
/>
<Button title="No" onPress={() => setSelectedIndex(-1)} />
</Modal>
The buttons in the Modal will rest the selected index or update the array.Something like the below function.
const updateSelectedItem = (index, value) => {
const updatedData = [...data];
updatedData[index].active = value;
setData(updatedData);
};
Sample code
https://snack.expo.io/#guruparan/verifypopup

You should enclose your SimpleModal component in the Modal, like this -
<Modal
transparent={true}
animationType='fade'
visible={isModalVisible}
nRequestClose={() => changeModalVisible(false)}
>
<SimpleModal/>
</Modal>

for modals use https://github.com/jeremybarbet/react-native-modalize
this library saved me a lot of days and pain developing modals in my app
if you are not using typescript, change the ref from
const modalizeRef = useRef<Modalize>(null);
to
const modalizeRef = useRef(null);

Related

React Native TextInput onFocus does not allow onPress of other child components

Nested TextInput component does not allow other components' onPress function to be called. Only when the TextInput is not focused, the onPress works fine.
React Native Version : 0.66.3
Here is my code
export const Component = (props): JSX.Element {
const { searchText, onChangeSearchText, onClearSearchText } = props
const [searchViewFocused, setSearchViewFocused] = useState<boolean>(false)
const searchIcon = searchViewFocused ? "searchActive" : "searchInactive"
const cancelIcon = searchViewFocused ? "cancelActive" : "cancelInactive"
return (
<View style={styles.searchBoxContainer}>
<View style={[styles.searchBox, searchViewFocused && styles.searchBarActive]}>
<Icon styles={styles.searchIcon} icon={searchIcon} />
<TextInput
style={styles.searchInput}
onChangeText={onChangeSearchText}
value={searchText}
onFocus={() => setSearchViewFocused(true)}
onBlur={() => setSearchViewFocused(false)}
autoCompleteType={"off"}
numberOfLines={1}
/>
{searchText !== "" && (
<Pressable style={styles.clearIcon} onPress={onClearSearchText}>
<Icon icon={cancelIcon} />
</Pressable>
)}
</View>
</View>
)
})
Attached are the images of
Expected.
VS
The issue
When the cross icon is pressed on focused state, the textInput is unfocused rather What I am trying to achieve is that the search text gets cleared & the input remains focused.
Note: The onPress works perfectly fine when input is not focused
Any help is appreciated. Thanks!
PS: Tried TouchableOpacity & also I have tried wrapping the components inside a ScrollView to use keyboardShouldPersistTaps='handled' as mentioned in one of the SO answer but to no success.
Found a workaround to this is to wrap the whole component into a ScrollView and adding the prop keyboardShouldPersistTaps='handled'
Previously I was making the View inside the Component as ScrollView and adding keyboardShouldPersistTaps='handled' which did not work
export const Component = (props): JSX.Element {
...
return (
<ScrollView contentContainerStyle={styles.searchBoxContainer}
keyboardShouldPersistTaps='handled'>
...
</ScrollView>
)
})
The key was to wrap the entire component inside the ScrollView,
Here's what worked:
<ScrollView keyboardShouldPersistTaps='handled'>
<Component {...props}/>
</ScrollView>
Guess this was a silly mistake, but worth pointing out!
You're setting the focus of the entire component based on whether the TextInput has focus. Since the clear button is outside the text input, pressing it causes the component to lose focus.
One solution is to store the TextInput instance in a ref. When the clear button is pressed, you can refocus the text input. I've copied your component below and added some new lines, which are marked in comments.
export const Component = (props): JSX.Element {
const { searchText, onChangeSearchText, onClearSearchText } = props
const textInputRef = useRef(null); // new
const [searchViewFocused, setSearchViewFocused] = useState<boolean>(false)
const searchIcon = searchViewFocused ? "searchActive" : "searchInactive"
const cancelIcon = searchViewFocused ? "cancelActive" : "cancelInactive"
const onClear = () => {
onClearSearchText();
textInputRef.current?.focus();
} // new
return (
<View style={styles.searchBoxContainer}>
<View style={[styles.searchBox, searchViewFocused && styles.searchBarActive]}>
<Icon styles={styles.searchIcon} icon={searchIcon} />
<TextInput
ref={textInputRef} // new
style={styles.searchInput}
onChangeText={onChangeSearchText}
value={searchText}
onFocus={() => setSearchViewFocused(true)}
onBlur={() => setSearchViewFocused(false)}
autoCompleteType={"off"}
numberOfLines={1}
/>
{searchText !== "" && (
<Pressable style={styles.clearIcon} onPress={onClear}> // calls new function
<Icon icon={cancelIcon} />
</Pressable>
)}
</View>
</View>
)
})

Issues with Modals React Native

everyone. I'm new in this new tecnology and I'm having a little problem with modals.
I'm programming a modal that only shows when a condition is true, in the first click it's all ok, but in the second the modal won't show, then when I click again, the window appears again, and continue successively.
The code works as follow: I have 3 states, each represent a different text to show in the modal. Then, I have a modal, that recieves a message (to print) and the state to identifies what state i need to show. And finally, in the main, I have a condition who calls the modal and show it ONLY if the state is true.
I checked the states with console.log and the only issue i find is that in some cases, the state is set in true, when is false, but i don't know why!
Thanks for read!
Here i detach part of the code.
Declare of the states in the main
const [modalVisibleEnTermino, setModalVisibleEnTermino] = useState(false)
const [modalVisibleFueraTermino, setModalVisibleFueraTermino] = useState(false)
const [modalVisibleRefuerzoTermino, setModalVisibleRefuezoTermino] = useState(false)
Condtition in main to show the apropiate state of modal
const setModal = () => {
vacunas ===2 && (days>6 && days<150) ? setModalVisibleEnTermino(true) : setModalVisibleFueraTermino(true)
if(vacunas == 3)
setModalVisibleRefuezoTermino(true)
}
Function to reset the states after showing modal (IDK if its ok)
const restoreModals = () => {
if (modalVisibleEnTermino) setModalVisibleEnTermino(false)
if (modalVisibleFueraTermino) setModalVisibleFueraTermino(false)
if (modalVisibleRefuerzoTermino) setModalVisibleRefuezoTermino(false)
}
After set the modal, I checked what state it's true, and I passed the values in this condition
{modalVisibleEnTermino && <MyModal
message={"Mensaje1"}
state={modalVisibleEnTermino}
/>
}
{modalVisibleFueraTermino && <MyModal
message={"Mensaje2."}
state={modalVisibleFueraTermino}
/>
}
{modalVisibleRefuerzoTermino && <MyModal
message={"Mensaje3."}
state={modalVisibleRefuerzoTermino}
/>
}
Modal
export const MyModal = (props) => {
const [visibleModal, setVisibleModal] = useState(props.state)
return (
<Modal visible={visibleModal}
transparent={true}
animationType='slide'
>
<View style={styles.container}>
<Text style={styles.titulo_label}>¡IMPORTANTE!</Text>
<Text style={styles.info_label}>{props.message}</Text>
<TouchableOpacity style={styles.button_aceptar} onPress={() => setVisibleModal(false)}>
<Text style={styles.text_button}>Aceptar</Text>
</TouchableOpacity>
</View>
</Modal>
);
Add a restore property to your MyModal component
{modalVisibleEnTermino && <MyModal
message={"Mensaje1"}
state={modalVisibleEnTermino}
restore={restoreModals}
/>
}
{modalVisibleFueraTermino && <MyModal
message={"Mensaje2."}
state={modalVisibleFueraTermino}
restore={restoreModals}
/>
}
{modalVisibleRefuerzoTermino && <MyModal
message={"Mensaje3."}
state={modalVisibleRefuerzoTermino}
restore={restoreModals}
/>
}
In the MyModal Component remove the useState and pass the props.state to visible and use the props.restore on the onPress callback like so
export const MyModal = (props) => {
return (
<Modal visible={props.state}
transparent={true}
animationType='slide'
>
<View style={styles.container}>
<Text style={styles.titulo_label}>¡IMPORTANTE!</Text>
<Text style={styles.info_label}>{props.message}</Text>
<TouchableOpacity style={styles.button_aceptar} onPress={() => props.restore()}>
<Text style={styles.text_button}>Aceptar</Text>
</TouchableOpacity>
</View>
</Modal>
);
In your original MyModal Component, by passing the props.state to useState, you are creating a new state within that component. Setting onPress to setVisibleModal(false) will not change the states of modalVisibleEnTermino, modalVisibleFueraTermino, and modalVisibleRefuerzoTermino. By passing restoreModals as a prop to MyModal you can change the states in the Main component from inside MyModal.
One more thing, remove the if statements in your restoreModals function
const restoreModals = () => {
setModalVisibleEnTermino(false)
setModalVisibleFueraTermino(false)
setModalVisibleRefuezoTermino(false)
}

Why my modal does not show up in react native iOS. But its working in react native android

I am in the strange situation. I always develop my app using android simulator. Since running two simulators both iOS and android always turn my pc into oven.
I am using redux in this app.
I got a component called cart. Whenever user tried to access this component I am testing if the user got item added to the cart or not. I am using useEffect hook to test it.
My cart component look like this
//Fetch cart data
let cartList = useSelector((state) => state.productReducer.cartList);
useEffect(() => {
if (cartList?.OrderDTO?.Id === null) {
setModalVisible(true);
//alert("your Cart is empty")
}
}, []);
useEffect(() => {
if (cartList?.OrderDTO?.Id === null) {
setModalVisible(true);
//alert("your Cart is empty")
}
}, [cartList]);
return (
<ScrollView style={styles.pageContainer}>
<Loader loading={loading} />
<View>
<NotiDialog
modalVisible={modalVisible}
setVisible={setModalVisible}
contentText="Your cart is empty"
comfirmText="OK"
comfirm={() => handleEmptyCart()}
titleText="Notification"
/>
<ComfirmDialog
modalVisible={modalTwoVisible}
setVisible={setModalTwoVisible}
contentText="Are you sure you want to empty the cart? "
comfirmText="OK"
comfirm={() => emptyTheCart()}
titleText="Notification"
/>
</View>
I already fetch cartData once when the app is loaded
As you can see in the useEffect I am using setModalVisible(true) to show up the modal.
But the problem is that this modal popup in android always. I already tried about 100 times. But in iOS its never show up
So instead of modal I tried to open up the ***commented*** alert in iOS. The message your Cart is empty popup. But the modal doesn't. So is there something wrong with my modal?
Here is my modal component
import {
...,
Modal,
} from 'react-native';
const NotiDialog = ({
modalVisible,
setVisible,
comfirm,
comfirmText,
contentText,
titleText,
}) => {
const confirmFunc = () => {
comfirm();
setVisible(false);
};
return (
<View style={styles.centeredView}>
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}>
<View style={styles.centeredView}>
...
</View>
</Modal>
</View>
);
};
try setTimeout() before opening the modal

Change state from custom button in React Native

I'm just starting at React native and i want to update the state from my home page with a click on a custom button.
I made this code juste bellow. When I click on my buttons, i can't see the state change.
const Home = () => {
const welcomeSentence =
"Bonjour, est ce que tu as fais ton workout aujourd'hui ?";
const [isWorkoutDone, setIsWorkoutDone] = useState(false);
return (
<View style={styles.container}>
<Text style={styles.homePageText}>{welcomeSentence}</Text>
<View style={styles.buttonContainer}>
<AppButton title ="OUI" onPress={()=>this.setIsWorkoutDone(true)}/>
<AppButton title ="NON" onPress={()=>this.setIsWorkoutDone(false)}/>
</View>
<Text>{isWorkoutDone ? "OK" : "KO"}</Text>
</View>
);
};
With this code on my cutom button :
const AppButton = (props) => {
return (
<Button
title={props.title}
onPress={props.onPress}
style={styles.appButton}
/>
);
};
I tested and make search but I didn't find why my state didn't change.
You are using functional component so you don't need this.
<AppButton title ="OUI" onPress={()=>setIsWorkoutDone(true)}/>
<AppButton title ="NON" onPress={()=>setIsWorkoutDone(false)}/>

Switch view depending on button click

I am new to react native.
My question is pretty simple: my screen contains 5 buttons. Each one opens the same < Modal > component. I need to dynamically change the content of the modal, depending on the button clicked.
For example:
if I click the first button, a text input will be shown into the modal.
If I click the second button, checkboxes will be shown into the modal.
Here's my modal :
<Modal
visible={this.state.modalVisible}
animationType={'slide'}
onRequestClose={() => this.closeModal()}>
<View style={style.modalContainer}>
<View style={style.innerContainer}>
<Text>This is content inside of modal component</Text>
<Button
onPress={() => this.closeModal()}
title="Close modal"
>
</Button>
</View>
</View>
</Modal>
Here I open it :
openModal() {
this.setState({ modalVisible: true });
}
Here I call the function (on button press) :
onPress={() => this.openModal()}
I've heard about using props/children, but I don't know how to use them is this case.
Can anyone please help ?
Here is quick example to show who to render different content based on input you provide.
Modal Content
renderModalContent(type, data) {
switch(type) {
1: {
return (
<View>{..data}</View>
)
}
2: {
return (
<Button>...</Button>
)
}
default: (<CustomComponent data={data} />)
}
}
Modal
<Modal>
<View>
{this.renderModalContent(this.state.type, this.state.modalContentData)}
</View>
</Modal>
Here you decide which view you want to render and pass its data.
openModal() {
this.setState({ modalVisible: true, type: 1, data: {...} });
}
You should modify your Modal component so that it renders the base layout with space for dynamic content to be rendered. The content will be passed in as children, via Props. This will mean the modal is dynamic and will / should support future requirements. Try to avoid the switch case in the modal render suggestion unless you have very specific requirements that are unlikely to change in the future, or if you want to do things the React way.
Then for each variant of your Modal (TextInput, Checkbox etc.) create a new Component that wraps the Modal component and have each button initiate rendering the specific component.
If you're using Redux then you would be creating containers, connecting to Redux and passing dynamic state variables. You don't have to use Redux but the principle is the same.
Here's a very basic example to illustrate my point.
// Basic modal that renders dynamic content
const Modal = props => {
const { children } = props;
render (
<View style={styles.modal} >
{children}
</View>
);
}
// Specific modal implementation with TextInput
const ModalWithTextInput = props => (
<Modal>
<TextInput
value={props.someValue}
/>
</Modal>
)
// Specific modal implementation with Switch
const ModalWithSwitch = props => (
<Modal>
<Switch
value={props.someValue}
/>
</Modal>
)
Then in your component that launches the modals, do something like this...
class MyComponent extends Component {
openTextModal = () => {
this.setState({ modalType: 'text' });
}
openSwitchModal = () => {
this.setState({ modalType: 'switch' });
}
renderModal = (type) => {
if (type === 'text') {
return(<ModalWithTextInput />)
}
if (type === 'switch') {
return(<ModalWithSwitch />)
}
}
render() {
const { modalType } = this.state;
render (
<View>
<View>
<TouchableWithX onPress={this.openTextModal} />
<TouchableWithX onPress={this.openSwitchModal} />
</View>
<View>
{this.renderModal(modalType)}
</View>
</View>
);
}
}
Please note this code has not tested but the principle is sound.

Resources