React Native: How to add two Actions to a button ? - react-native

I have a small problem. I want to pass down two Actions to a Button, but I can't seem to figure it out. I am using the react-native-router-flux library. I tried something like this, but It doesn't really work.
If anyone could help that would be awesome. Thanks !
<Button
onPress={Actions.Main1 && Actions.Tab2}
style={{ width: 90, height: 90 }} >
<Text>Show</Text>
</Button>

The onPress prop takes a function, and only a function. There is no syntax for automatically combining two funtions in Javascript. You need to create a new function which executes both actions.
<Button
onPress={(e) => {
Actions.Main1(e);
Actions.Tab2(e);
}}
style={{ width: 90, height: 90 }} >
<Text>Show</Text>
</Button>
Some notes:
I passed the event parameter into both of the actions, since passing just one of the functions (i.e. onPress={Actions.Main1}) itself would pass this parameter as well. This may not be necessary in your case.
The slight issue with this code is that creates a new function every time the render function of this component is called. It's not terrible, but also not ideal. Consider that in the future. I include that optimization in this post because a) we don't see the rest of the implementation of the component, b) I think this question was rudimentary enough for us to just worry about the main concept.

Related

ScrollToLocation not working on initial mount

I'd like to add a SectionList to my app such that it renders to a specific section (that isn't the first section in the list). Calling scrollToLocation on componentDidMount does not work; however, adding a button that calls scrollToLocation does. Is there a reason for this?
Could this be due to the SectionList reference (I've tried a few approaches for assigning reference, e.g. variable assignment, function assignment, using createRef, etc.)?
Here is a link to a stripped-down Expo snack to illustrate what I mean: https://snack.expo.io/#bobbymoogs/scrolltolocation-on-componentdidmount.
I found the best solution on this thread is to use onLayout to trigger the scroll:
scrollToInitialPosition = () => {
this.scrollViewRef.scrollTo({ y: 100 });
}
...
<ScrollView
ref={(ref) => { this.scrollViewRef = ref; }}
onLayout={this.scrollToInitialPosition}
/>
Note there are lots of other suggestions using setTimeout, componentDidUpdate, InteractionManager, etc. However using onLayout was the only one that worked for me (and also seems to me to be the cleanest).

State update only affects component if it affects parents' style

I have an app that lets the user scan for and connect to BLE devices. If the user taps a scan result, I want a spinner to show next to the device while the connection is in progress.
I am using Redux to keep track of discovered and connected devices. The main App component is connect with redux-react and passes the relevant bits of state to its children.
One of these children is the list of scan results, which in turn passes one device to each of its entries. The scan list items look like this:
class DeviceListItem extends Component{
render = () => {
return <TouchableOpacity onPress={this.props.onPress}>
<Card>
<View style={{justifyContent: "space-between", flexDirection: "row", flex:1, width:"100%", alignItems: this.props.item.pendingActions !== 0?"flex-start":undefined}>
<Text>{this.props.item.name}</Text>
<ActivityIndicator animating= {this.props.item.pendingActions !== 0} color={Colors.accent} size="small"/>
</View>
</Card>
</TouchableOpacity>
}
}
Now, in the style of the View component you might notice this peculiar snippet of code:
alignItems: this.props.item.pendingActions !== 0?"flex-start":undefined
For some reason, this is required to make the spinner show up when the state of the device changes. It seems that in order to make the spinner show up on a state update is to make the style of the parent view depend on the state. It doesn't seem to matter which property changes, but it needs to change in some way in order for the spinner to be affected by the update.
Does anyone have an idea about what's going on here? I'm still fairly new to Redux and React Native so there's a chance I am misusing something here but this just seems odd to me.
When updating props the component isn't self-aware about props changes.
When you update the parent state, and the props has been changed, it will trigger a render at the parent, that will also re-render the child you are talking about.
When updating a prop value, without triggering a render, the child will not re-render.
To make it aware about props changes you have to use componentDidUpdate.
An example would be:
componentDidUpdate=(prevProps)=>{
if (prevProps!==this.props)
this.setState({propsChanged:!this.state.propsChanged})
}
To use the example above, you have to define a state variable called propsChanged.
Hope this helps you understand the problem and find a solution that suits you!

Background with two colors - React Native

Is there a way to have a background with two colors as follows: Two colors
I tried expos Linear Gradient, but that's Gradient. I'm not sure how to put two colors in the main View tag as background ?
Any suggestions?
If the dimensions of the view doesn't get you anywhere, try to manipulate its borders, for example, try this code:
import React, { Component } from 'react'
import { View, Dimensions } from 'react-native'
const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window')
class App extends Component {
render() {
return (
<View style={{ flex: 1 }}>
<View
width: SCREEN_WIDTH,
height: 0,
borderTopColor: "blue",
borderTopWidth: SCREEN_HEIGHT / 2,
borderRightWidth: SCREEN_WIDTH,
borderRightColor: 'transparent'
/>
</View>
)
}
}
export default App
And it gives you:
Off Topic
I still don't understand why people dislike questions like this. Yes there's no code posted, but it doesn't mean he didn't try anything. Maybe he did, but none of the methods he tried was anywhere near the answer, then why should he post the code up here to make the question lengthy, just to prove that he did try? And, even if he didn't try much, maybe it's because he had no clue what to try, isn't that a possibility?
There are many questions without any code posted but got hundreds of upvotes, such as "How to remove an element from an array in JavaScript?". Really? I honestly think if you even read the documentation and tried some methods such as .splice, .reduce, .unshift, you would've figured that out without having to ask it here on SO. Those questions were popular because they made a lot of beginners (including me) lives easier, not because those questions showed that whoever asked it made a great amount of effort. And this question certainly is a good one in that sense. (But maybe he should change the title of the question to make it more specific, because it would benefit others when they goole it)

Trying to remove a view index above child count error

What does this mean?
This happens when I update a list of iterated views something like
<View style={{ flexDirection: 'row', padding: 20, backgroundColor: '#fff' }}>
<Ionicons name={jobIcon} color={theme.iconColor} size={30} />
<Text>{jobService}</Text>
<Text>{jobDate}</Text>
</View>
mapped inside a scrollview.
this error pops up when I modify the array from child scene.
scene1 - is where the ScrollView with job list array of views
sence2 - is where I delete a job and should update scene1 when I do remove a job
If you want the LayoutAnimation to work with ScrollView, replace
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
with
LayoutAnimation.configureNext({
duration: 300,
create:
{
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.opacity,
},
update:
{
type: LayoutAnimation.Types.easeInEaseOut,
}
});
This works on both Android and iOS without any crashes.
In my case I was using LayoutAnimation for my ScrollView. Inside it a map of Items. When an Item is removed from the list this happens. Not using LayoutAnimation seems to be working fine.
It's happening when you call layout animation when it already in process. iOS will show an warning while Android will explode with this error.
You can use this easy pattern to fix it when you're using LayoutAnimation from same component.
layoutAnimation() {
if (!this.layoutAnimationActive) {
this.layoutAnimationActive = true;
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInOut, () => { this.layoutAnimationActive = false; });
}
}
This happens when a component only has x amount of children, but you are trying to remove a child with index greater than x. Like an index out of bounds exception that is common with arrays. Can cause lots of frustration because often times the child you are trying to remove DOES INFACT EXIST. But might be happening because you are using a third party component that only expects a certain amount of children.
For me, it happened when I put an extra child into air-bnb MapView. I fixed the issue by making this element the child of it's grandparent (it was absolutely positioned so it didn't affect styling).
I encountered this issue when creating a react-native application using Expo.
This error was often getting raised when I was rendering new Markers onto a Map (which was rendered via a MapView component).
What fixed the issue for me was to add a key prop to the Marker component e.g.
<Marker coordinate={coordinate} key={`${coordinate.latitude}_${coordinate.longitude}`} />
Hope this helps anyone who also encounters this issue when dealing with MapView and Marker components!
In my case, I was deleting an item in a virtualized list. I was using redux to manage the data of the list and updated the list with the new data. However, the component for the item that was deleted caused this error.
I solved this by adding a boolean state property on this item component, example "hideItem". My item was a class component but a setState hook could also be used for a functional component. I set this to true after deletion. The post hid with layout animation correctly, and when the page refreshed it no longer rendered the deleted item. Hence, the error went away on android without needing to not use LayoutAnimation.
Evidently, it seems this bug can show its ugly face in various conditions. After a couple of hours of debugging, I found my root cause to be a key prop being passed to a component that didn't require it. I'm still unsure of why this was causing a crash, however, I suspect it has to do with the fact that the component accepts the key as a unique way to identify the view, but was also using the componentWillReceiveProps(props: *) lifecycle method that updated the component's state.
This is likely to happen if you're using some native components, where some ViewManager returns a LayoutShadowNode in createShadowNodeInstance of ViewGroupManager or something extending ReactShadowNode in createShadowNodeInstance of ViewManager on Android, and a RCTShadowView in the shadowView method of RCTViewManager on iOS. But, returns null/nil for some other View in some other ViewManager.
Then, if you combine children of both types in the same parent, and any of the elements without shadowViews/Nodes come before the changing number of elements which do have shadowViews/Nodes, then the indices won't match up, and the RCTUIManager on iOS and NativeViewHierarchyManager on Android will choke and produce these exceptions.
I solved a similar issue in react-native-svg recently, by making all the ViewManagers return values rather than null/nil. https://github.com/facebook/react-native/issues/23350
So, try upgrading react-native-svg to v9.2.4 and the issue might be fixed. Or, try moving the IonIcons to the end of your children.
I had the same issue, because I had an Array.map inside a condition which I was updating using LayoutAnimation.
I fixed it by moving the state variable inside the map function.
I am using vitalized flatlist with swipe left right delete option, and when list is more than 200 items and I use LayoutAnimation then the above problem comes out on arbitrary based, I figured out that deleted item still exist because of LayoutAnimation so you can play around with timings of update using the following code
LayoutAnimation.configureNext({
duration: 300,
create:
{
duration:500
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.opacity,
},
update:
{
duration: 500,
type: LayoutAnimation.Types.easeInEaseOut,
}
});
this.refs['task'].setNativeProps({
style: {transform: [{translateX: Dimensions.get('window').width}]},
});
one more thing, I am also hiding the item suddenly after it's deletion occurs
here is code snippet
this.props.handleDeleteTask(this.props.item.id);
this.setState({hideItem:true}) // here I am hiding through state function, so the item should disappear right after it's deletion.

React Native - What is the benefit of using StyleSheet vs a plain object?

What exactly is the benefit of using StyleSheet.create() vs a plain object?
const styles = StyleSheet.create({
container: {
flex: 1
}
}
Vs.
const styles = {
container: {
flex: 1
}
}
There is no benefit. Period.
Myth 1: StyleSheet is more performant
There is absolutely no performance difference between StyleSheet and an object declared outside of render (it would be different if you're creating a new object inside render every time). The performance difference is a myth.
The origin of the myth is likely because React Native team tried to do this, but they weren't successful. Nowhere in the official docs you will find anything about performance: https://facebook.github.io/react-native/docs/stylesheet.html, while source code states "not implemented yet": https://github.com/facebook/react-native/blob/master/Libraries/StyleSheet/StyleSheet.js#L207
Myth 2: StyleSheet validates style object at compile time
This is not true. Plain JavaScript can't validate objects at compile time.
Two things:
It does validate at runtime, but so does when you pass the style object to a component. No difference.
It does validate at compile time if you're using Flow or TypeScript, but so does once you pass the object as a style prop to a component, or if you properly typehint object like below. No difference either.
const containerStyle: ViewStyle = {
...
}
Quoting directly from comment section of StyleSheet.js of React native
Code quality:
By moving styles away from the render function, you're making the code easier to understand.
Naming the styles is a good way to add meaning to the low level components in the render function.
Performance:
Making a stylesheet from a style object makes it possible to refer to it by ID instead of creating a new style object every time.
It also allows to send the style only once through the bridge. All subsequent uses are going to refer an id (not implemented yet).
Also StyleSheet validates your stylesheet content as well. So any error of incorrect style property is shown at time of compiling rather than at runtime when StyleSheet is actually implemented.
The accepted answer is not an answer to the OP question.
The question is not the difference between inline styles and a const outside the class, but why we should use StyleSheet.create instead of a plain object.
After a bit of researching what I found is the following (please update if you have any info).
The advatanges of StyleSheet.create should be the following:
It validates the styles
Better perfomances because it creates a mapping of the styles to an ID, and then it refers inside with this ID, instead of creating every time a new object. So even the process of updating devices is faster because you don't send everytime all the new objects.
It used to be considered that using a StyleSheet was more performant, and was recommended for this reason by the RN team up until version 0.57, but it is now no longer recommended as correctly pointed out in another answer to this question.
The RN documentation now recommends StyleSheet for the following reasons, though I think these reasons would apply equally to plain objects that are created outside of the render function:
By moving styles away from the render function, you're making the
code easier to understand.
Naming the styles is a good way to add meaning to the low level
components in the render function.
So what do I think are the possible benefits of using StyleSheet over plain objects?
1) Despite claims to the contrary my testing on RN v0.59.10 indicates that you do get some validation when calling StyleSheet.create() and typescript (and probably flow) will also report errors at compile time. Even without compile time checking I think it's still beneficial to do run time validation of styles before they are used for rendering, particularly where components that use those styles could be conditionally rendered. This will allow such errors to be picked up without having to test all rendering scenarios.
2) Given that StyleSheet is recommended by the RN team they may still have hopes of using StyleSheet to improve performance in future, and they may have other possible improvements in mind as well, for example:
3) The current StyleSheet.create() run-time validation is useful, but a bit limited. It seems to be restricted to the type checking that you would get with flow or typescript, so will pick up say flex: "1" or borderStyle: "rubbish", but not width: "rubbish" as that could be a percentage string. It's possible that the RN team may improve such validation in future by checking things like percentage strings, or range limits, or you could wrap StyleSheet.create() in your own function to do that more extensive validation.
4) By using StyleSheet you are perhaps making it easier to transition to third party alternatives/extensions like react-native-extended-stylesheet that offer more.
So, today, September of 2021, after reading all the answers and doing some researches, I created a summary about using Stylesheet instead of a plain object.
Based on React Documentation, you should use the stylesheet when the complexity starts to grow.
The style prop can be a plain old JavaScript object. That's what we usually use for example code.
As a component grows in complexity, it is often cleaner to use StyleSheet.create to define several styles in one place.
In the simulator, when using stylesheet will display an ERROR, and when using the plain object will display only a WARNING.
Based on item 2, it looks like it has some validation while compiling. (A lot of people say that’s a myth)
If you need to migrate for a third-party library in the future, for some of them like react-native-extended-stylesheet, if you are using stylesheet, it will be easier.
You have some methods and properties that boost the development. For example, the property StyleSheet.absoluteFill will do position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, or the method compose() will allow you to combine two styles, overriding it.
P.S.: The performance answer looks to be a myth.
My opinion?
Based on item 2 and 5, go to stylesheet instead of plain objects.
I did not find any differences between StyleSheet and plain object, except of typing validation in TypeScript.
For example, this (note the typing differences):
import { View, Text, Image, StyleSheet } from 'react-native';
import logo from './logo.svg';
export default class App extends Component {
render() {
return (
<View style={styles.someViewStyle}>
<Text style={styles.someTextStyle}>Text Here</Text>
<Image style={styles.someImageStyle} source={logo} />
</View>
);
}
}
const styles: StyleSheet.create({
someViewStyle: {
backgroundColor: '#FFF',
padding: 10,
},
someTextStyle: {
fontSize: 24,
fontWeight: '600',
},
someImageStyle: {
height: 50,
width: 100,
},
});
equals to this:
import { View, Text, Image, ViewStyle, TextStyle, ImageStyle } from 'react-native';
import logo from './logo.svg';
export default class App extends Component {
render() {
return (
<View style={styles.someViewStyle}>
<Text style={styles.someTextStyle}>Text Here</Text>
<Image style={styles.someImageStyle} source={logo} />
</View>
);
}
}
const styles: {
someViewStyle: ViewStyle;
someTextStyle: TextStyle;
someImageStyle: ImageStyle;
} = {
someViewStyle: {
backgroundColor: '#FFF',
padding: 10,
},
someTextStyle: {
fontSize: 24,
fontWeight: '600',
},
someImageStyle: {
height: 50,
width: 100,
},
};
Creating your styles via StyleSheet.create will pass though validation only when global variable __DEV__ is set to true (or while running inside Android or IOS emulators see React Native DEV and PROD variables)
The function source code is pretty simple:
create < +S: ____Styles_Internal > (obj: S): $ReadOnly < S > {
// TODO: This should return S as the return type. But first,
// we need to codemod all the callsites that are typing this
// return value as a number (even though it was opaque).
if (__DEV__) {
for (const key in obj) {
StyleSheetValidation.validateStyle(key, obj);
if (obj[key]) {
Object.freeze(obj[key]);
}
}
}
return obj;
}
I would recommend using it because it performs run-time validation during development, also it freezes the object.
i know that this is a really late answer, but I've read that it shows you errors and provides auto completion in editors when you use StyleSheet.