Why divs are flashing? - reactjs

I'm new to React Virtualized, and sorry for my English.
This is my code pen link: http://codepen.io/anon/pen/xqGXwv?editors=0010,
when I scroll to the 4th div, it's flashing, could someone help me ?

You forgot to accept and set the style parameter. This parameter is very important for react-virtualized because it's what positioned the rows as you scroll down. Here's your render function, fixed:
renderPage({index, key, style}) {
const color = ['green', 'red', 'black', 'yellow'][index % 4]
return (
<div
style={{ ...style, width: 400, height: 200, backgroundColor: color }}
key={key}
>
No.{index + 1}
</div>
)
}

Related

Making signaturePad component take up full screen

Within one of my components a user can click a button that pulls up a signaturePad they can sign on. This is working, however, I'd like the signaturePad to take up the full screen, whereas now it appears between the footer and header. How can I accomplish this? I played around with using { flex: 1 } on the View of the SignaturePad, but this had no visible effect.
Here is the relevant code from the parent component. If a certain state is true, the signaturePad displays:
{this.state.signaturePanelIsVisible && (
<SignaturePanel
session={this.props?.session}
signaturePanelIsVisible={this.state.signaturePanelIsVisible}
/>
)}
And the signaturePad component code looks like this:
const SignaturePanel = (props) => {
const dispatch = useDispatch();
return (
<SignaturePanel
actionStyle={{
...styles.texts.mediumText,
color: styles.colors.primary,
textDecorationLine: 'underline',
}}
onCancel={async () => {
props.hideSignaturePanel();
}}
onSave={async (base64) => {
const base64Result = base64.base64DataUrl.substr(base64.base64DataUrl.indexOf(',') + 1);
dispatch(
await updateSignature({
...props.signature,
guid: props.session.guid,
value: base64Result,
lastUpdate: Date.serverTime(),
})
);
}}
/>
);
};
export default SignaturePanel;
And the styling applied looks like this:
container: {
width: '100%',
height: '100%',
zIndex: 98,
position: 'absolute',
backgroundColor: '#fff',
},
You'll need to add position: 'absolute' to the style of your modal. Setting the height and width to 100% as well sometimes works, depending on how your app is set up. This will either cover the screen with the component, or make the component appear under the header and overflow the bottom of the screen. To fix the latter issue, add top: -<height of header>. This way the component will move up and cover the header.
<Modal style={styles.modal}>
<View style={styles.signaturePad}>
</View>
</Modal>
modal: {
position: 'absolute',
height: '100%',
width: '100%',
top: -n, //(where n = height of your header)
}
signaturePad: {
height: '100%',
width: '100%',
}
Depending on how your project is set up, you may not need the top value. These are general settings that you should usually put on a modal component. It's considered best practice to have a modal cover the whole screen, then add the component you want to display as a subcomponent.

react native : custom component with color parameter

Im doing the exercises to learn react native on codecademy.
I am told "In React, properties are passed as objects on the first parameter to our components. You need to add this parameter in the custom component and use the color property as the background color."
I need to pass color as a parameter to my Box custom component. This is my code:
export const Box = (color) => (
<View color={color} style={{ width: 100, height: 100, backgroundColor: this.props.color }} />
);
It throws me a syntax error.
I also tried :
export const Box = (color) => (
<View style={{ width: 100, height: 100, backgroundColor: color }} />
);
But I am told "View should have a background color set by the color property.". It's the same when I do
export const Box = (color) => (
<View style={{ width: 100, height: 100, backgroundColor: {color} }} />
);
It's very basic but I'm always mistaken when it comes to calling variables in React and properly using them...
If you could help me that would be great!
thanks
Basically, you can get props like this:
export const Box = ( props ) => (
<View color={props.color} style={{ width: 100, height: 100, backgroundColor: props.color }} />);

How to make react-modal scrollable?

Im trying to make my modal (react-modal node package) scrollable (There is an img inside)
here is my code:
content: {
position: 'absolute',
backgroundColor: '#FFF',
padding: '15px',
zIndex: '1000',
width: '90%',
borderRadius: '.5em',
},
overlay: {
position: 'fixed',
display: 'flex',
justifyContent: 'center',
top: '0',
left: '0',
width: '100%',
height: '100%',
backgroundColor: 'rgba(0,0,0, .8)',
zIndex: '1000',
overflowY: 'auto',
},
}
Modal.setAppElement('#__next')
export const langContext = React.createContext()
export default function Home() {
const [isEn, setIsEn] = useState(true)
const [modalIsOpen, setIsOpen] = useState(false)
const { width } = useWindowDimensions()
function openModal() {
setIsOpen(true)
}
function closeModal() {
setIsOpen(false)
}
function updateLang() {
setIsEn((isEn) => !isEn)
}
return (
<langContext.Provider value={{ isEn, updateLang }}>
<div id="modal" className="overflow-hidden relative">
<Header />
<Modal
isOpen={modalIsOpen}
onRequestClose={closeModal}
style={customStyles}>
<div className="relative m-h-[1000px] h-full w-full overflow-y-scroll">
{isEn ? (
<Image
layout="fill"
objectFit={width >= 750 ? 'fill' : ' cover'}
quality={100}
src={
width >= 750 ? '/assets/menu-en.png' : '/assets/Menu_en_m.png'
}
alt="Menu"
/>
) : (
<Image
layout="fill"
objectFit={width >= 750 ? 'fill' : ' cover'}
quality={100}
src={
width >= 750 ? '/assets/menu-he.png' : '/assets/Menu_he_m.png'
}
alt="Menu"
/>
)}
</div>
</Modal>
</div>
</langContext.Provider>
)
}
Any ideas on how can I do it? (I'm trying to play with the overflow and position element but I can't find the proper solution
The scrolling suppose to happen on Mobile and the Image dimensions are: 550*1550 (I can resize it if necessary)
Right now the image is cut
Thanks for the helpers!
I think your modal is good in terms of vertical scrolling, but the problem has may come from this line
objectFit={width >= 750 ? 'fill' : 'cover'}
Your mobile dimension is 500*1550 which means the image will take object-fit:cover;
You can check object-fit:cover; definition here
The image keeps its aspect ratio and fills the given dimension. The image will be clipped to fit
If you already check the dimension to load the device-respective image, you can remove the condition to check for cover.
object-fit:fill is sufficient for your case
The change can be
objectFit="fill"
Another potential problem I can see here that you have layout="fill" for that image which will make it absolute. The image container has relative which restricts the original size of your image.
To fix it, you may need to remove relative from the image container too.

is it possible to animate a strikethrough with React Spring?

I'm new to React Spring and I initially tried this
const strikeProps = useSpring({
textDecoration: "line-through",
from: { textDecoration: "none" },
});
But it's not working. I think there should be a way simulate the CSS solution for this.
The problem here is, that the original CSS solution is uses pseudo element for emulating the strike trough. We can only add react-spring properties for normal html elements. So the most compact way is to create a separate strike through component for this problem. For example:
const StrikeTroughtText = ({ children, weight = 1 }) => {
const props = useSpring({
from: { width: "0%" },
to: { width: "100%" }
});
return (
<div style={{ position: "relative", display: "inline-block" }}>
{children}
<animated.div
style={{
position: "absolute",
top: "50%",
left: 0,
width: props.width,
height: `${weight}px`,
background: "black"
}}
/>
</div>
);
};
We basically animate the width of the absolutely positioned div containing a black line over the text.
You can use it like a div component:
<StrikeTroughtText>text</StrikeTroughtText>
For bigger font size the default 1 px line weight is not enough, so I added a weight property also.
Here is my example: https://codesandbox.io/s/react-strike-trought-text-component-with-react-spring-animation-86cfd?file=/src/App.js

How to dynamically set height of a component whose height is an animated value post-animation?

The goal: have a dropdown view that animates the height-expansion over time. the caveat is this: once the view is expanded, it needs to be able to dynamically handle whether or not there is additional view data present. if it is present, a couple extra text components will be rendered.
The problem: as it currently is, the animation the parent's height to a fixed height. so when the additionalContent is rendered, it surpasses the bounds of the parent, whose height is fixed. I dont want to not set the height of the parent explicitly, because then I cant animate that aspect the way I want. I want to maintain the height animation as-is, as well as dynamically size the parent to contain the children when the additionalContent is present
const ListItem = (props) => {
const [checkInModal, setCheckInModal] = useState(false);
const [animatedHeight, setAnimatedHeight] = useState(new Animated.Value(0))
const [animatedOpacity] = useState(new Animated.Value(0))
const [dynamicHeight, setDynamicHeight] = useState(0);
const [expanded, setExpanded] = useState(false);
const toggleDropdown = () => {
if (expanded == true) {
// collapse dropdown
Animated.timing(animatedHeight, {
toValue: 0,
duration: 200,
}).start()
} else {
// expand dropdown
Animated.timing(animatedHeight, {
toValue: 100,
duration: 200,
}).start()
}
setExpanded(!expanded)
}
const renderAdditionalContent = () => {
setDynamicHeight(75);
if (someVariable == true) {
return (
<View> <Text> Some Content </Text> </View>
)
}
}
const interpolatedHeight = animatedHeight.interpolate({
inputRange: [0, 100],
outputRange: [75, 225]
})
const interpolatedOpacity = animatedOpacity.interpolate({
inputRange: [0, 100],
outputRange: [0.0, 1.0]
})
return (
<Animated.View
style={[styles.container, { height: interpolatedHeight + dynamicHeight }]}
>
<View style={{ flexDirection: 'row', justifyContent: 'space-between', }}>
<View style={styles.leftContainer}>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Text style={styles.title}>{props.title}</Text>
</View>
<Text style={styles.subtitle}>{time()}</Text>
</View>
<View style={styles.rightContainer}>
<TouchableOpacity onPress={() => toggleDropdown()} style={styles.toggleBtn}>
<Image source={require('../assets/img/chevron-down.png')} resizeMode={'contain'} style={styles.chevron} />
</TouchableOpacity>
</View>
</View>
{expanded == true ? (
<Animated.View style={[styles.bottomContainer, { opacity: interpolatedOpacity }]}>
<Components.BodyText text="Subject:" style={{ fontFamily: Fonts.OPENSANS_BOLD }} />
<Components.BodyText text={props.subject} />
{ renderAdditionalContent() }
</Animated.View>
) : null}
</Animated.View>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: '#fff',
borderRadius: 25,
width: width * 0.95,
marginBottom: 5,
marginHorizontal: 5,
paddingVertical: 15,
paddingHorizontal: 15
},
leftContainer: {
justifyContent: 'space-between',
},
rightContainer: {
flexDirection: 'row',
alignItems: 'center'
},
title: {
fontFamily: Fonts.OPENSANS_BOLD,
fontSize: 20,
color: '#454A66'
},
subtitle: {
color: '#454A66',
fontSize: 14
},
typeIcon: {
height: 25,
width: 25
},
chevron: {
height: 15,
width: 15
},
toggleBtn: {
borderWidth: 1,
borderColor: Colors.PRIMARY_DARK,
borderRadius: 7,
paddingTop: 4,
paddingBottom: 2.5,
paddingHorizontal: 4,
marginLeft: 10
},
bottomContainer: {
marginVertical: 20
},
buttonContainer: {
flexDirection: 'row',
width: 250,
justifyContent: 'space-between',
alignSelf: 'center',
marginVertical: 20
},
noShadow: {
elevation: 0,
shadowOffset: {
width: 0,
height: 0
},
shadowRadius: 0,
}
});
export default ListItem;
How can this be accomplished? So far ive tried creating a state variable dynamicHeight and setting it inside the function that renders additional content, but that hasn't worked.
Heres the snack: https://snack.expo.io/P6WKioG76
clarification edit: renderAdditionalContent function renders additional content (obviously), this content could be anywhere from one line of characters to multiple lines. regardless of the char count, the main parent container of the component needs to have all the children within its bounds. as it stands, if the additional-content-rendered has too much content, the content will spill over the border of the component's main parent container, which must be avoided. this can be done by simply not giving a height to the main component container, obviously. but the the idea is to have the animated height AND wrap the child content properly
Any suggestions?
EDITED : easy and simple way
You can also apply the height 100%, in that way we don't need to calculate the height of inner content it will auto adjust as per the content provided
const interpolatedHeight = animatedHeight.interpolate({
inputRange: [0, 100],
outputRange: ["0%", "100%"] // <---- HERE
})
To make this happen I have added <View> tag around the <Animated.View> to get height 100% correct and few changes in css, this looks more elegant and provides a perfect solution to your problem.
WORKING DEMO
So, you can use onLayout
This event is fired immediately once the layout has been calculated
First step:
// setHeight
const setHeight = (height) => {
setDynamicHeight(prev => prev + height);
}
<View onLayout={(event) => {
var { x, y, width, height } = event.nativeEvent.layout;
setHeight(height); // <--- get the height and add it to total height
}}>
<Text>Subject</Text>
<Text>Subject Content</Text>
{renderAdditionalContent()}
</View>
Second step:
useEffect(() => {
// trigger if only expanded
if (expanded) {
// trigger height animation , whenever there is change in height
Animated.timing(animatedHeight, {
toValue: dynamicHeight, // <--- animate to the given height
duration: 200,
}).start();
}
}, [dynamicHeight]); // <--- check of height change
WORKING DEMO (you can test it by adding remove text)
Here's a working snack of your code with a dynamic dropdown height: https://snack.expo.io/4mT5Xj6qF
You can change the height by changing the thisIsAValue constant.
Honestly you were very close with your code, you just had a few bits and pieces missing:
When you're animating height you don't need to use interpolate, you can let the <Animated.View> straight up calculate the height. The interpolation is needed if you want to animate, for example, a rotation, and you need to calculate the degrees to which the element must move.
You need to pass your dynamic height into the animation, as your to: value
I set up a simple useEffect hook checking for changes in the someVariable and dynamicHeight prop
This solution will let you set the height dynamically through a prop.
However if you want to calculate the height based on elements which are present in the View you may want to check #vivek-doshi 's answer
You can use React refs. This allows you to access a component directly.
const el = React.useRef(null);
Assign el to the ref of the container div of whatever content you have. Then hide/show the div using the visibility style:
<div style={{ visibility: !expanded && "hidden" }} ref={el}>
<View /* snip */>
{ renderAdditionalContent() }
/* -- snip -- */
</View>
</div>
Then in the toggleDropdown function you can access the height of the component via the .current.offsetHeight property:
Animated.timing(animatedHeight, {
toValue: el.current.offsetHeight,
duration: 200,
}).start()
Refs can be used on any html element and allow you to access the element's raw properties. Animations are probably one of the most common use cases for them.
Demo: https://snack.expo.io/heLsrZNpz
You can read more here: https://reactjs.org/docs/refs-and-the-dom.html

Resources