I'm trying to understand the best practice for naming component styles in react-native. I understand that style-sheets are scoped at component level but I want to understand if i have two different components whether its bad to use the same css class name for different styles in different components. For example:
component one:
render() {
return (
<View style={styles.container}>
</View>
)
}
const componentOneStyles = StyleSheet.create({
container: {
backgroundColor: 'red'
}
});
component two:
render() {
return (
<View style={styles.container}>
</View>
)
}
const componentTwoStyles = StyleSheet.create({
container: {
backgroundColor: 'green'
}
});
Given this example is it ok to use container for both these components or would it be better practice to use containerOne and containerTwo.
Related
I am learning react-native and am very new to it. So, when I was learning to use flexbox, I ran into an issue. The issue was, the views are not being displayed when inside another view. My code =
import React from "react";
import { View, StyleSheet } from "react-native";
class App extends React.Component {
render() {
return (
<View style={styles.container}>
<View backgroundColor="red" />
<View backgroundColor="blue" />
<View backgroundColor="green" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
},
});
export default App;
If you run this program, you will get a blank screen. I don't know why this is happening, and I also want to know how to fix it. By the way, I am running it in Iphone 11 simulator
You have set BackgroundColor directly to the View which is not possible. It has to be in the "Style" param. Also you have no height and width set to the View.
You can either do it inside the View directly like this:
<View style={{ backgroundColor: "red", height: 20, width: "100%"}} />
or create a new Style in your StyleSheet and then pass that to the View.
I have a prop called isProfile which is used by a component (Feed) that uses the stylesheet below. I want to conditionally render the height of the container based on whether the isProfile prop is set as true or false.
function Feed({isProfile}){
return(
<View style={style.container}>
</View>
)
}
const styles = StyleSheet.create({
container:{
backgroundColor:colors.primary,
width:windowWidth,
justifyContent:"center",
height: isProfile ? windowHeight : windowHeight*0.87,
},
You should change styles to a function that accepts the parameter:
function Feed({isProfile}){
return(
<View style={createStyles(isProfile).container}>
</View>
)
}
const createStyles = (profile) => StyleSheet.create({
container:{
backgroundColor:colors.primary,
width:windowWidth,
justifyContent:"center",
height: profile ? windowHeight : windowHeight*0.87,
},
The isProfile variable (prop) is local to the component and invisible outside, so it must be passed as the parameter
You can store mutiple styles by using an array of objects for style style={[{},{}]} etc.. This allows you to add the second part I added
function Feed({isProfile}){
return(
<View style={[style.container,{height: isProfile ? windowHeight : windowHeight*0.87,}]}>
</View>
)
}
const styles = StyleSheet.create({
container:{
backgroundColor:colors.primary,
width:windowWidth,
justifyContent:"center",
},
I am trying to pass the fontSize as a style property to my component. The fontSize doesnt change any ideas how I can pass the fontSize as a prop to overwrite the default size?
<Homemenu navigation={navigation} style={styles.homeMenu} />
const styles = StyleSheet.create({
....
homeMenu: {
fontSize: 16,
},
});
In my homeMenu:
render() {
let {style, navigation} = this.props;
let fontSize = style && style.fontSize ? style.fontSize : null;
return (
<View style={styles.container}>
<View style={[styles.menuItem, fontSize]}>
....
</View>
const styles = StyleSheet.create({
...
menuItem: {
fontSize: 26
},
});
I guess you are unnecessary bother for falsy values in style prop. I don't see any issue of why it shouldn't work. Code looks good to me.
<Homemenu navigation={navigation} style={styles.homeMenu} />
const styles = StyleSheet.create({
...
homeMenu: {
fontSize: 16,
},
});
render() {
let { style, navigation } = this.props;
return (
<View style={styles.container}>
<View style={[styles.menuItem, style]}>
....
</View>
</View>
);
}
const styles = StyleSheet.create({
...
menuItem: {
fontSize: 26
},
});
You are doing it correct, the only change you need to make in
<View style={[styles.menuItem, fontSize]}>
is you should update the existing style object
style={{...styles.menuItem, fontSize}}
Basically it should be iterable, so that your second value can overrride the first one. And we should not enclose it with square brackets and we should use curly braces, since it is object.
I have some references in a React Native Web application - these references work on React Native, but not RNW.
For example, I have this code:
this.highlight.current._children[i].setNativeProps({ style: { backgroundColor: "black" } });
this.highlight.current._children[i]._children[0]._children[0].setNativeProps({ style: { color: "white" } })
this.highlight.current._children[i]._children[1]._children[0].setNativeProps({ style: { color: "white" } })
Which is based on this:
this.highlight = React.createRef();
Which is passed into a child component as a prop and used as such:
<View ref={this.props.highlight}>
It has several children (who have nested children as well).
However, on the web, there is no ._children at all.
How do I access children?
It's possible to do DOM manipulation directly if Platform.OS === 'web':
let dom = ReactDOM.findDOMNode(this.highlight.current);
... DOM manipulations
But this feels messy and code-duplicating if not absolutely necessary. I'd much rather apply my modifications to the reference directly via the React Native API.
EDIT: More code - here's my structure and a few relevant functions to the problem. I cut out irrelevant parts to try to make the code I posted smaller
class DetailBody extends Component {
constructor() {
super();
}
render() {
return (
<ScrollView >
<Text>{this.props.article.intro}</Text>
<View ref={this.props.highlight}>
{this.props.article.json.results.map((content, index) => (
<View key={index} style={{}}>
{content.pinyin ? (
<Fragment>
<View>
<Text>
{content.pinyin}
</Text>
</View>
<View>
<Text>
{content.simplified}
</Text>
</View>
</Fragment>
) : (
<Fragment>
<View>
<Text>
</Text>
</View>
<View>
<Text>
{content.characters}
</Text>
</View>
</Fragment>
)
}
</View>
))}
</View>
</ScrollView>
)
}
}
class Detail extends Component {
constructor() {
super();
this.state = {
currentVal: 0,
};
this.traverseCharacters = this.traverseCharacters.bind(this)
this.highlight = React.createRef();
}
async traverseCharacters(i) {
this.highlight.current._children[i].setNativeProps({ style: { backgroundColor: "black" } });
this.highlight.current._children[i]._children[0]._children[0].setNativeProps({ style: { color: "white" } })
this.highlight.current._children[i]._children[1]._children[0].setNativeProps({ style: { color: "white" } })
if (i > 0) {
this.clearCharacters(i)
}
}
render() {
return (
<DetailBody {...this.props} article={this.state.article} highlight={this.highlight} />
);
}
}
[Edit]: Since this 'someone's work' is for class component, here is one of my answer using dynamic refs with a functional component : Dynamic refs with functional component. It uses a useRef() hooks to store your dynamic refs, and so they're accessible wherever you want, with a specific id.
After trying things for a moment now, I cannot find a clean way of doing what you want to do. However, there is solutions for this, as you said with the ReactDOM. Another thing that came in my mind would be to set your refs in your child and then pass it to the parent.
Here is someone doing 'dynamic' ref in a .map using the key attribute, maybe it can be of use to you : Someone's work
Now, using direct manipulation isn't a good practice, so using this isntead of ReactDOM.findDOMNode... I don't really know which is one is worse but both are messy i guess.
setNativeProps isn't available on the children element. You either need to provide a refs to the intended child elements yourself before calling setNativeProps on them
For a ref solution you could make use of ref callbacks like below and add a ref to each and every element that you wish to update dynamically
class DetailBody extends Component {
setRef = (i, j, ref) => {
if(this.highlight[i]) {
this.highlight[i][j] = ref;
} else {
this.highlight[i] = {[j]: ref};
}
}
render() {
return (
<ScrollView >
<Text>{this.props.article.intro}</Text>
<View>
{this.props.article.json.results.map((content, index) => (
<View key={index} style={{}} ref= {(ref) => this.setRef(index, 'root', ref)}>
{content.pinyin ? (
<Fragment>
<View ref= {(ref) => this.setRef(index, 0, ref)}>
<Text>
{content.pinyin}
</Text>
</View>
<View ref= {(ref) => this.setRef(index, 1, ref)}>
<Text>
{content.simplified}
</Text>
</View>
</Fragment>
) : (
<Fragment>
<View ref= {(ref) => this.setRef(index, 0, ref)}>
<Text>
</Text>
</View>
<View ref= {(ref) => this.setRef(index, 1, ref)}>
<Text>
{content.characters}
</Text>
</View>
</Fragment>
)
}
</View>
))}
</View>
</ScrollView>
)
}
}
class Detail extends Component {
constructor() {
super();
this.state = {
currentVal: 0,
};
this.traverseCharacters = this.traverseCharacters.bind(this)
this.highlight = {};
}
async traverseCharacters(i) {
this.highlight[i].root.setNativeProps({ style: { backgroundColor: "black" } });
this.highlight[i][0].setNativeProps({ style: { color: "white" } })
this.highlight[i][1].setNativeProps({ style: { color: "white" } })
}
render() {
return (
<DetailBody {...this.props} article={this.state.article} highlight={this.highlight} />
);
}
}
This question already has answers here:
Passing Styles Based on Parent Component in React Native
(2 answers)
Closed 5 years ago.
I have a custom component called CardSection
import React from 'react';
import { View } from 'react-native';
const CardSection = (props) => {
return (
<View style={styles.containerStyle}>
{props.children}
</View>
);
};
const styles = {
containerStyle: {
borderBottomWidth: 1,
padding: 5,
backgroundColor: '#fff',
justifyContent: 'flex-start',
flexDirection: 'row',
borderColor: '#ddd',
position: 'relative'
}
};
export { CardSection };
When I instantiate this component from another class I would like to update one of the style elements while the others remain unchanged. The code below will only update the justifyContent element.
<CardSection style={{ justifyContent: 'space-between' }}>
The solution I have at the minute does not seem to be working and I would like to avoid duplicating the element with just a change to one of the style elements.
You could do the following:
//destruct props
const CardSection = ({ style, children }) => {
return (
// prop 'style' overrides standard containerStyle
<View style={[styles.containerStyle, style]}>
{children}
</View>
);
};
You can merge styles if you pass an array to styles:
const CardSection = (props) => {
return (
<View style={[styles.containerStyle, props.style]}>
{props.children}
</View>
);
};
They 'cascade' from left to right, meaning that latter styles in the array overwrite the former.
Here is the documentation for styling in react-native by default.