How to handle ScrollView inside a Pressable in React-Native? [duplicate] - javascript

This question already has answers here:
React-Native, Scroll View Not Scrolling
(13 answers)
Closed 1 year ago.
Right now, I am creating a modal with items inside the modal to scroll. However, I am noticing the touch function is being extremely obscured and not passing through appropriately. With this current implementation, scrolling on the ScrollView is not working. I am just trying to have this scrollview inside the modal, I have set it up so that the modal can be pressable inside and an outside press of the modal will cause it to close. So I need to pass the proper touchable properties down.
Some resources and previous stack overflow pages I was looking at was:
React-Native, Scroll View Not Scrolling
return (
<Container {...props}>
<BottomModal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}>
<CenterView onPress={() => setModalVisible(!modalVisible)}>
<ModalContent>
<ModalHeader>
<CloseButtonContainer>
<Pressable onPress={() => setModalVisible(!modalVisible)}>
<CloseButton
name="times-circle"
type={vectorIconTypes.MEDIUM}
/>
</Pressable>
</CloseButtonContainer>
<TitleContainer>
<TitleText>{title}</TitleText>
</TitleContainer>
</ModalHeader>
<ModalList>
<ScrollContainer>
<LeftTextRightCheckBox>
<TitleText>Newest</TitleText>
<CheckBox />
</LeftTextRightCheckBox>
<LeftTextRightCheckBox>
<TitleText>Points High to Low</TitleText>
<CheckBox />
</LeftTextRightCheckBox>
<LeftTextRightCheckBox>
<TitleText>Brands A to Z</TitleText>
<CheckBox />
</LeftTextRightCheckBox>
<LeftTextRightCheckBox>
<TitleText>Brands A to Z</TitleText>
<CheckBox />
</LeftTextRightCheckBox>
<LeftTextRightCheckBox>
<TitleText>Brands A to Z</TitleText>
<CheckBox />
</LeftTextRightCheckBox>
<LeftTextRightCheckBox>
<TitleText>Brands A to Z</TitleText>
<CheckBox />
</LeftTextRightCheckBox>
<LeftTextRightCheckBox>
<TitleText>Brands A to Z</TitleText>
<CheckBox />
</LeftTextRightCheckBox>
<LeftTextRightCheckBox>
<TitleText>Brands A to Z</TitleText>
<CheckBox />
</LeftTextRightCheckBox>
</ScrollContainer>
</ModalList>
</ModalContent>
</CenterView>
</BottomModal>
</Container>
...
const Container = styled.View`
flex-direction: column;
background-color: white;
padding: 10px;
`;
const BottomModal = styled.Modal`
flex-direction: row;
height: 100%;
`;
const CenterView = styled.Pressable`
justify-content: flex-end;
align-items: center;
background-color: rgba(0, 0, 0, 0.3);
height: 100%;
`;
const ModalContent = styled.Pressable`
flex-direction: column;
background-color: white;
width: 100%;
border-top-left-radius: 50px;
border-top-right-radius: 50px;
padding-bottom: 30px;
height: 300px;
`;
const ModalHeader = styled.View`
flex-direction: row;
width: 100%;
padding: 20px;
height: 60px;
`;
const ModalList = styled(ScrollView).attrs(() => ({
contentContainerStyle: {
flexDirection: 'column',
justifyContent: 'center',
flexGrow: 1,
},
showsVerticalScrollIndicator: true,
persistentScrollbar: true,
}))`
border: solid pink 5px;
width: 100%;
height: 200px;
padding: 10px;
`;

My question was answered perfectly in the same link I had in my question. All credit goes to freddrivett.
If your ScrollView is within something that handles touch (Pressable,
TouchableWithoutFeedback etc) then you either need to stop the touch
event propagating up to that parent handler or else the ScrollView
won't handle the touch event and therefore won't scroll.
This can be done either with onStartShouldSetResponder={() => true} or
by wrapping the children in an element which itself handles the touch
event (e.g. Pressable):
<Pressable>
<Text>This is scrollable</Text>
<Pressable>
<Pressable>
<Text>As is this</Text>
<Pressable> </ScrollView> );

Related

How to place any button outside the dialog box

I want a close button that needs to work outside the dialog box.
I want this modal where the close button is outside div.
Expected:
Implementation:
const Component = styled(Box)`
display: flex;
height: 528px;
`;
const Image = styled(Box)`
width: 270px;
background: url(https://static-assets-web.flixcart.com/www/linchpin/fk-cp-zion/img/login_img_c4a81e.png)
no-repeat;
color: #fff;
background-color: #2874f0;
background-position: 50% 85%;
padding: 40px 33px;
& > p {
margin-top: 12px;
color: #dbdbdb;
font-size: 18px;
}
`;
const ReqBtn = styled(Button)`
background-color: #fb641b;
text-transform: none;
height: 48px;
width: 305px;
padding: 10px 20px 10px 20px;
`;
const Wrapper = styled(Box)`
padding: 56px 35px 16px 35px;
& > p {
color: #878787;
font-size: 12px;
}
`;
// <--------------------------------------- styled section ends-------------------------------->
const LoginDialog = ({ open, setOpen }) => {
const handleCloseDialog = () => {
setOpen(false);
};
return (
<Dialog
open={open}
onClose={handleCloseDialog}
sx={{
"& .MuiDialog-container": {
"& .MuiPaper-root": {
width: "100%",
maxWidth: "750px",
},
},
}}
>
<Component>
<Image>
{/* <Typography
style={{ fontWeight: "bold", fontSize: "28px", color: "#fff" }}
>
Login
</Typography>
<Typography>
Get access to your Orders, Wishlist and Recommendations
</Typography> */}
</Image>
<Wrapper>
{/* <TextField label="Enter Email/Mobile Number" variant="standard" />
<Typography>
By continuing, you agree to Flipkart's Terms of Use and Privacy
Policy.
</Typography>
<ReqBtn
variant="contained"
sx={{
"&.MuiButtonBase-root:hover": { backgroundColor: "#fb641b" },
}}
>
Request OTP
</ReqBtn>
<Typography>New to Flipkart?Create an Account</Typography> */}
</Wrapper>
//close button
<ClearIcon
onClick={handleCloseDialog}
style={{ cursor: "pointer", backgroundColor: "yellow" }}
/>
</Component>
</Dialog>
);
};
export default LoginDialog;
I tried pasting the <ClearICon> outside <Dialog> component but the issue is the close button came in my navbar position
<>
<ClearIcon
onClick={handleCloseDialog}
style={{ cursor: "pointer", backgroundColor: "yellow" }}
/>
</>
How can I place the CloseIcon outside the dialog box as per provided design?
something like this...
.box{
position:relative;
background:gray;
width:100px;
height:100px;
}
.box>.controls{
position:absolute;
right:-30px;
}
<div class="box">
<div class="controls">
<button>x</button>
</div>
</div>

Intersection Observer isVisible variable not changing

I have set up this Intersection Observer function because I want my divs to slide in from the side as the user scrolls down. However, after much tinkering and small changes, it still is not working. I've tried console-logging "entries", the "isVisible" variable, and "sliderRef". The first two are useless, as I get undefined for isVisible and an empty array for "entries", while I get the first div when I console-log sliderRef, but not the other two divs. I apologize for the vagueness and inability to present a specific reason as to why this isn't working. Any help would be appreciated, or any suggestion for a simpler way to achieve what I'm trying to do. Below is all the relevant code:
Edit: I changed the default value of isVisible to true, to see if the props were even being passed to my styled components, and the div appeared briefly on load but then slid out of view. However, still nothing happens when I have isVisible set to false. My options don't seem to be being taken into account, because the function was triggered regardless of the fact that I had not yet reached the threshold, which is 0.5
import { useRef, useState, useEffect} from 'react'
import styled, { css } from 'styled-components'
import PropTypes from 'prop-types';
import clsx from 'clsx';
import {
Container,
Grid,
Typography,
makeStyles
} from '#material-ui/core';
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "white",
height: "200vh",
marginBottom: "200px"
},
contentGrid: {
display: "flex",
height: "33%",
padding: 0,
},
}));
const useElementOnScreen = (options) => {
const sliderRef = useRef(null);
const [isVisible, setIsVisible] = useState(false);
const callBackFunction = (entries) => {
const [entry] = entries;
setIsVisible(entry.IsIntersecting);
console.log(entries);
};
useEffect(() => {
const observer = new IntersectionObserver(callBackFunction, options);
if (sliderRef.current) observer.observe(sliderRef.current);
return () => {
if (sliderRef.current) observer.unobserve(sliderRef.current);
};
}, [sliderRef, options]);
return [sliderRef, isVisible];
}
function Features({ className, ...rest }) {
const classes = useStyles();
const [sliderRef, isVisible] = useElementOnScreen({
root: null,
threshold: 0.5,
rootMargin: "0px 0px -100px 0px"
})
return (
<div
className={clsx(classes.root, className)}
{...rest}
>
{/* <Container maxWidth="lg" style={{padding: 0, width: "100%"}}> */}
<Grid className={classes.contentGrid} style={{backgroundColor: "#025373"}}>
<SliderFromLeft visible={isVisible}
ref={sliderRef}
style={{backgroundColor: "#F2D680"}}
>
<Typography
variant="h4">
Increased complexity has enabled media agencies
to create opaque financial structures
and then inflate their fees and
media prices at will, while many
advertisers are stuck behind contracts
unfit for modern media buying that
provide little scope for transparency and accountability.
</Typography>
</SliderFromLeft>
<NonSlider style={{alignItems: "center", paddingRight:"75px"}}>
<Typography
variant="h1"
align="right"
style={{color:"#F2C230", fontSize:"4rem"}}
>
Are you getting the most out of your contract?
</Typography>
</NonSlider>
</Grid>
<Grid className={classes.contentGrid} style={{backgroundColor: "#D0E5F2"}}>
<NonSlider style={{backgroundColor: "#D0E5F2"}}>
<Typography
variant="h1"
style={{color: "#025373", fontSize:"4rem"}}
>
The <br/>Challenge
</Typography>
</NonSlider>
<SliderFromRight visible={isVisible}
style={{backgroundColor: "#75B8BF"}}
>
<Typography
variant="h4"
style={{color:"#025373"}}>
We want you to get the same benefits that the top global advertisers enjoy.
The core of a successful relationship between you and your media agency is a well thought-out contract.
<br/>
<br/>
You must ensure that your media agency contract provides clarity and accountability,
and contains competitive terms and conditions.
</Typography>
</SliderFromRight>
</Grid>
<Grid className={classes.contentGrid} style={{backgroundColor: "#F2D680"}}>
<SliderFromLeft visible={isVisible}
style={{backgroundColor:"#F2F2F2"}}
ref={sliderRef}
>
<Typography
variant="h4">
It is known that most media agencies design their own contract templates to benefit
themselves and not you. We believe this needs to change and you need to regain control.
<br/>
<br/>
To assess the quality of your contract, you must first benchmark it against the industry average.
Once you know the the strengths and weaknesses of the contract, it is easier to
know what needs to be improved upon.
</Typography>
</SliderFromLeft>
<NonSlider style={{alignItems: "center", justifyContent:"right", paddingRight: '75px'}}>
<Typography
variant="h1"
align="right"
style={{color:"#025373", fontSize:"4.2rem"}}
>
The <br/> Solution
</Typography>
</NonSlider>
</Grid>
{/* </Container> */}
</div>
);
}
const SliderFromLeft = styled.div`
height: 100%;
width: 50%;
display: flex;
align-items: center;
padding: 0 75px 0 75px;
border-top-right-radius: 30px;
border-bottom-right-radius: 30px;
opacity: 0%;
transform: translateX(-100%);
transition: transform 400ms ease-in, opacity 250ms ease-in;
${props => props.visible && `
transform: translateX(0%);
opacity: 100;`
}
`
const SliderFromRight = styled.div`
height: 100%;
width: 50%;
display: flex;
align-items: center;
padding: 0 75px 0 75px;
border-top-left-radius: 30px;
border-bottom-left-radius: 30px;
opacity: 0;
transform: translateX(100%);
transition: transform 400ms ease-in, opacity 250ms ease-in;
${props => props.visible && `
transform: translateX(0%)
opacity: 100;`
}
`
const NonSlider = styled.div`
height: 100%;
width: 50%;
display: flex;
align-items: center;
padding: 0 75px 0 75px
`
Features.propTypes = {
className: PropTypes.string
};
export default Features;```
For anyone having the same issue, despite reorganizing and improving my code based on updated documentation, I didn't exactly solve my problem, but I did somewhat achieve the effect I was looking for. I'm still not sure what was causing the issue, but I decided to ditch the slide-in effect for a simple fade-in effect by changing the opacity, and that works just fine.
Based on the newer documentation I found and some other answers here on SO, you can just import the useInView hook instead of writing it out yourself, and you must call useInView separately for each component, instead of giving all components the same ref and calling useInView once. I hope this helps.
import { useRef, useState, useEffect} from 'react';
import { useInView } from 'react-intersection-observer';
import styled, { css } from 'styled-components'
import PropTypes from 'prop-types';
import clsx from 'clsx';
import {
Container,
Grid,
Typography,
makeStyles
} from '#material-ui/core';
import Contract from './Media/contract.png'
import Challenge from './Media/challenge.png'
import Presenter from './Media/presenter.png'
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "white",
height: "175vh",
},
contentGrid: {
display: "flex",
height: "33%",
padding: 0,
},
header: {
color: "#000000",
fontSize: "2.5rem",
marginBottom: "10px",
},
image: {
height: "355px",
width: "500px",
}
}));
function Features({ className, ...rest }) {
const classes = useStyles();
const { ref: ref1, inView: inView1 } = useInView({ threshold: 0.5 })
const { ref: ref2, inView: inView2 } = useInView({ threshold: 0.5 })
const { ref: ref3, inView: inView3 } = useInView({ threshold: 0.5 })
console.log(inView2);
return (
<div
className={clsx(classes.root, className)}
{...rest}
>
{/* <Container maxWidth="lg" style={{padding: 0, width: "100%"}}> */}
<Grid className={classes.contentGrid}>
<SliderFromLeft
visible={inView1}
ref={ref1}
>
<Typography
variant="h1"
align="left"
className={classes.header}
>
Are you getting the most out of your contract?
</Typography>
<Typography
variant="h4">
Increased complexity has enabled media agencies
to create opaque financial structures
and then inflate their fees and
media prices at will, while many
advertisers are stuck behind contracts
unfit for modern media buying that
provide little scope for transparency and accountability.
</Typography>
</SliderFromLeft>
<NonSlider style={{alignItems: "center", paddingRight:"75px"}}>
<img src={Contract} className={classes.image} />
</NonSlider>
</Grid>
<Grid className={classes.contentGrid}>
<NonSlider>
<img className={classes.image} src={Challenge} />
</NonSlider>
<SliderFromRight
visible={inView2}
ref={ref2}
>
<Typography
variant="h1"
align="right"
className={classes.header}
>
The Challenge
</Typography>
<Typography
variant="h4"
>
We want you to get the same benefits that the top global advertisers enjoy.
The core of a successful relationship between you and your media agency is a well thought-out contract.
<br/>
<br/>
You must ensure that your media agency contract provides clarity and accountability,
and contains competitive terms and conditions.
</Typography>
</SliderFromRight>
</Grid>
<Grid className={classes.contentGrid}>
<SliderFromLeft
visible={inView3}
ref={ref3}
>
<Typography
variant="h1"
align="left"
className={classes.header}
>
The Solution
</Typography>
<Typography
variant="h4">
It is known that most media agencies design their own contract templates to benefit
themselves and not you. We believe this needs to change and you need to regain control.
<br/>
<br/>
To assess the quality of your contract, you must first benchmark it against the industry average.
Once you know the the strengths and weaknesses of the contract, it is easier to
know what needs to be improved upon.
</Typography>
</SliderFromLeft>
<NonSlider style={{alignItems: "center", justifyContent:"right", paddingRight: '75px'}}>
<img src={Presenter} className={classes.image} />
</NonSlider>
</Grid>
{/* </Container> */}
</div>
);
}
const SliderFromLeft = styled.div`
height: 100%;
width: 50%;
// display: flex;
align-items: center;
padding: 75px 75px 0 75px;
border-top-right-radius: 30px;
border-bottom-right-radius: 30px;
opacity: 0;
// transform: translateX(-100%);
transition: transform 400ms ease-in, opacity 0.5s ease-in;
${props => props.visible && `
// transform: translateX(0%);
opacity: 100;`
}
`
const SliderFromRight = styled.div`
height: 100%;
width: 50%;
// display: flex;
align-items: center;
padding: 75px 75px 0 75px;
border-top-left-radius: 30px;
border-bottom-left-radius: 30px;
opacity: 0;
// transform: translateX(100%);
transition: transform 400ms ease-in, opacity 0.5s ease-in;
${props => props.visible && `
// transform: translateX(0%)
opacity: 100;`
}
`
const NonSlider = styled.div`
height: 100%;
width: 50%;
display: flex;
align-items: center;
padding: 0 75px 0 75px
`
Features.propTypes = {
className: PropTypes.string
};
export default Features;```

Button works on emulator but not on smartphone on React Native

I have had a problem for several days, I have a list of items (a list of heads) and I want to be able to take action on these items (update/ delete).
I created an item component, with an update and delete button.
The Button component is a component of react native elements, I use it everywhere in my app and I have not had any problems so far.
ThemeItem.tsx
<Container>
<List onPress={() => onSelectTheme(theme.id)}>
<ListItem.Content>
<View
style={{display: 'flex', flexDirection: 'row', marginBottom: 5}}>
<ListItem.Title style={{fontSize: 18, fontWeight: 'bold'}}>
{theme.name}
</ListItem.Title>
{isActive && (
<Icon
name={'check-circle'}
color={'green'}
style={{marginLeft: 5}}
size={20}
/>
)}
</View>
</ListItem.Content>
</List>
<ThemeItemIconsStyle>
<>
{theme.id > 1 && !isActive && (
<Button
onPress={() => onDelete(theme.id)}
icon={{
name: 'trash',
type: 'font-awesome-5',
size: 25,
color: 'white',
}}
/>
)}
<Button
onPress={() => onUpdate(theme)}
icon={{
name: 'pen',
type: 'font-awesome-5',
size: 25,
color: 'white',
}}
/>
</>
</ThemeItemIconsStyle>
</Container>
ThemeItemIconStyle
const ThemeItemIconsStyle = styled.View`
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
padding: 15px 20px;
background-color: white;
width: 40%;
height: 100%;
`;
Container
const Container = styled.View`
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
background-color: white;
`;
On emulator the behavior is the one expected but when I install the apk on my phone it does not happen absolutely.
I absolutely do not understand why my code works on emulator and not on a real phone. I assume that if on emulator there is no problem, the problem does not come from the code.
Thanks in advance for help
But what is the type of button? Button, TouchableOpacity, TouchableOpacityWithoutFeedback...
Also, I'd recommend to change your buttons to RectButton from react-native-gesture-handler, just to use native buttons in your application ;)

How to test the state of a functional component in React with Jest (No Enzyme)

Hi everybody how can I test the state of a functional component from the useState hook?
This my component:
const Container = styled.div
display: flex;
flex: 1;
flex-direction: row;
align-items: ${props => props.hasSubtitle ? 'flex-start' : 'center'};
opacity: ${props => props.disabled ? 0.5 : 1.0};
${props => props.style}
const Button = styled.button
padding: 0;
border: none;
background: none;
cursor: pointer;
outline: none;
const TextContainer = styled.div
display: flex;
flex: 1;
flex-direction: column;
margin-left: 12px;
const CheckBox = props => {
const [selected, setSelected] = useState(false);
useEffect(() => {
setSelected(props.selected);
}, [props.selected]);
return (
<Container data-testid={'checkbox'} style={props.style} hasSubtitle={props.subtitle}>
<Button
data-testid={'checkBtn'}
onClick={() => {
if(!props.disabled){
setSelected(!selected);
if(props.onChange) props.onChange(!selected);
}
}}
>
{selected ? <CheckBoxOn/> : <CheckBoxOff/>}
</Button>
<TextContainer>
<Text style={{fontSize: 16}}>
{props.title}
</Text>
{props.subtitle && <Text style={{fontSize: 12}}>{props.subtitle}</Text>}
</TextContainer>
</Container>
);
};
export default CheckBox;
How can I check the value of the state when I render the component with the selected props value to false and when I render it with selected prop to true?
And how I can test if the click event on the button trigger setSelected()? By the way we are not able to use Enzyme
Checking state in your tests lately has been considered a bad practice. What people generally recommend is to check the consequences of a state change: in your case, you could check the presence of CheckBoxOn.

How to get Children width in Reactjs

Here is an online sample https://codesandbox.io/s/jovial-resonance-5mjq0
const Parent = styled.div`
display: flex;
width: 100%;
background: yellow;
justify-content: space-between;
`;
const Children = styled.div`
display: flex;
background: tomato;
height: 50px;
flex: 0 0 10%;
`;
function App() {
return (
<Parent>
<Children />
<Children />
<Children />
<Children />
<Children />
</Parent>
);
}
So regardless the window resizing.
so pure javascript can be done like
document.querySelectorAll(CHILDREN).forEach(e=> {
e.clientWidth
})
but how to get <Children />'s width? I understand it may not common to play DOM in reactjs. But is there a react way to get width? Thanks
Use refs to get DOM elements (after rendering). If you need the width of multiple elements either use several refs and some arithmetic, or use an enveloping parent.
class MyComponent extends React.Component {
constructor() {
super();
this.elementRef = React.createRef();
}
componentDidMount() {
// get the BCR of your ref
const bcr = this.elementRef.current.getBoundingClientRect()
console.log({ width: bcr.width });
}
render() {
return (
<div style={{ width: '234px' }}>
<div ref={this.elementRef} style={{ width: '50%' }}>
Hello, World!
</div>
</div>
);
}
}
ReactDOM.render(<MyComponent />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Categories