Make Font Awesome component reusable in React - reactjs

Is there a way I can make my component reusable?
I am using react-native-fontawesome npm
here is the original component:
export default class Awesome extends Component {
render() {
return (
<View>
<TouchableHighlight>
<Text
style={{ margin: 10, fontSize: 15, textAlign: 'left' }}
>
<FontAwesome>{Icons.chevronLeft}</FontAwesome>//I want to change this line
Text
</Text>
</TouchableHighlight>
</View>
);
} }
I want to pass in my parent component something like:
<Awesome icon="chevronLeft" />
and then in my Awesome use
<FontAwesome>{Icons.this.props.icon}</FontAwesome>
Obviously this is not the way to do it, but I do not have any good ideas.

Found the way, I can use switch statement
<Awesome icon="Back" />
<Awesome icon="Heart" />
<Awesome icon="Share" />
<Awesome icon="More" />
and in my Child component:
export default class Awesome extends Component {
render() {
switch (this.props.icon) {
case 'Back':
return <FontAwesome>{Icons.chevronLeft}</FontAwesome>;
case 'Heart':
return <FontAwesome>{Icons.heart}</FontAwesome>;
case 'Share':
return <FontAwesome>{Icons.share}</FontAwesome>;
case 'More':
return <FontAwesome>{Icons.ellipsisH}</FontAwesome>;
default:
return <Text>HI</Text>;
}
}
}

Related

Invariant Violation: Element type is invalid: expected a string

I'm having this issue with ui kitten kit library, it works fine with regular but throw this error when I'm passing props. I tried to change my import / exports method with no luck. can please someone help figure it out.
import { RkTheme, RkButton, RkCard, RkText, rkCardContent, rkCardImg, rkCardFooter, } from 'react-native-ui-kitten';
...
export default class AutocompleteExample extends Component {
render() {
return (
<Content />
<RkCard>
<View rkCardHeader>
<Text>Header</Text>
</View>
<Image rkCardImg source={{uri: this.state.img}}/>
<View rkCardContent>
<Text>quick brown fox</Text>
</View>
<View rkCardFooter>
<Text>{this.state.price}</Text>
</View>
</RkCard>
)
}
module.exports = AutocompleteExample
this.state.img works well and I'm able to see the picture however this.state.price do not work, if replace it with a regular text it works. Thanks.
Rewriting the above code
import { RkTheme, RkButton, RkCard, RkText, rkCardContent, rkCardImg, rkCardFooter, } from 'react-native-ui-kitten';
...
export default class AutocompleteExample extends Component {
state = {
price: '',
}
render() {
return (
<Content />
<RkCard>
<View rkCardHeader>
<Text>Header</Text>
</View>
<Image rkCardImg source={{uri: this.state.img}}/>
<View rkCardContent>
<Text>quick brown fox</Text>
</View>
<View rkCardFooter>
<Text>{this.state.price}</Text>
</View>
</RkCard>
)
}
module.exports = AutocompleteExample

Adding margins to a component's children in React Native?

I have a few React Native components within a parent <View> component, and I wish to apply margins to each one of the <View>'s child components. Is there a straightforward way to set props or styles to this <View> to produce this result?
You can achieve this in both ways:
Applying styles to child itself
class Child extends Component {
render() {
return (
<View style={{ marginTop: 30, ... }}>
<Text>hi</Text>
</View>
)
}
}
or pass the styles to child component through props
class Parent extends Component {
render() {
return (
<View>
<Child styles={{ marginTop: 30 }} /> // passing styles to child
</View>
)
}
}
class Child extends Component {
render() {
return (
<View style={this.props.styles}> // setting styles from props
<Text>hi</Text>
</View>
)
}
}

React Native - Put child components into parent according to 'key' leads error

Here I am creating a react-native project which have installed react-navigation.
I have switch on the StackNavigator for pages across the application. Below is what I would like to archive.
I would like to use StackNavigator without using the provided header. Therefore I create a component <Header> like below:
export default class Header extends Component {
constructor(props) {
super(props);
}
detectKeyAndRender(item) {
if (item.key === "left") {
return <View style={leftContainerStyle}>{item}</View>;
} else if (item.key === "middle") {
return <View style={middleContainerStyle}>{item}</View>;
} else if (item.key === "right") {
return <View style={rightContainerStyle}>{item}</View>;
}
}
render() {
return (
<View key="header" style={headerContainerStyle}>
{ this.props.children.map((item) => ( this.detectKeyAndRender(item) )) }
</View>
);
}
}
Also for the common styles and container structure, I have created a component called <BaseContainer> like below:
import { getChildComponent } from 'helper.js';
export default class BaseContainer extends Component {
constructor(props) {
super(props);
}
render() {
return (
<SafeAreaView key="safe-area-view" style={safeAreaViewStyle}>
{ /* Please set the header from each page */ }
{ getChildComponent(this.props.children, "header") }
<View style={outerContainerStyle}>
<ScrollView contentContainerStyle={scrollViewStyle} alwaysBounceVertical={false}>
{ /* Page content goes in here */ }
{ getChildComponent(this.props.children, "content") }
</ScrollView>
</View>
</SafeAreaView>
);
}
}
And also the helper.js:
export function getChildComponent(children, key) {
return children.filter( (comp) => {
return comp.key === key;
});
}
Thus in other pages, I can call the header like below:
export default class FirstPage extends Component {
render() {
<BaseContainer>
<Header key="header">
<Text key="left">Left</Text>
<Text style={{color: '#fff', fontSize: 20}} key="middle">First Page</Text>
<Text key="right">Right</Text>
</Header>
<View key="content">
<Text>This is first page.</Text>
</View>
</BaseContainer>
}
}
export default class SecondPage extends Component {
render() {
<BaseContainer>
<Header key="header">
<Text key="left">Left</Text>
<Text style={{color: '#fff', fontSize: 20}} key="middle">Second Page</Text>
<Text key="right">Right</Text>
</Header>
<View key="content">
<Text>This is second page.</Text>
</View>
</BaseContainer>
}
}
This render method of <Header> will bring out an error but it's not fatal. The error is about the unique key:
Warning: Each child in an array or iterator should have a unique "key" props.
Check the render method of `Header`.
I know inside react native, every key should be unique (for performance issue).
Therefore I would like to ask is there any better method to put the specific child component into the header, or add the style according to a "key"? Appreciate for any help.
Please try to make the solution as simple as possible. Combine some common code together is what I would like to archive.
NOTE: I don't want to use the custom header inside react-navigation because the position it put is not what I want.
A simple way to get rid of the error would be to add a unique key to the View Components generated in detectKeyAndRender by adding a second parameter to it. So your function would be e.g. detectKeyAndRender(item, key).
Inside of the function simply add that key parameter to every returned View: <View key={key} ... />
Then when you actually map over the children, pass the index to the function:
{ this.props.children.map((item, i) => ( this.detectKeyAndRender(item, i) )) }
Unique keys should be given to each child element.
Header
export default class Header extends Component {
constructor(props) {
super(props);
}
detectKeyAndRender(item) {
/* you can use 'left,'middle' & 'right' as keys - they are different */
let { key } = item;
/* do validation on style hence you are not changing anything on view */
/* 'Conditional Operator' is used to simplify if...else...if...else */
let style =
key === "left"
? leftContainerStyle
: key === "middle"
? middleContainerStyle
: key === "right"
? rightContainerStyle
: middleContainerStyle /* default */;
return (
<View key={key} style={style}>
{item}
</View>
);
}
render() {
return (
<View key="header" style={headerContainerStyle}>
{this.props.children.map(item => this.detectKeyAndRender(item))}
</View>
);
}
}

React Native : undefined is not an object

I am currently learning React Native.
I just a built a very simple app to test out the Button component.
When I click on the button component the console log is printed as expected.
But after printing out the console log it pops out the following error.
**undefined is not an object (evaluating '_this2.btnPress().bind')**
I am not sure what is wrong ?
Can anyone let me know what I am doing wrong ?
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
export default class App extends React.Component {
btnPress() {
console.log("Fn Button pressed");
}
render() {
return (
<View style={styles.container}>
<Button title="this is a test"
onPress={()=> this.btnPress().bind(this)} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
You are invoking the function instead of passing a reference through bind.
loose the ().
And you should not wrap it with an arrow function as bind is already returning a new function instance
onPress={this.btnPress.bind(this)} />
By the way, this will return and create a function instance on each render, you should do it once in the constructor (which runs only once):
export default class App extends React.Component {
constructor(props){
super(props);
this.btnPress = this.btnPress.bind(this);
}
btnPress() {
console.log("Fn Button pressed");
}
render() {
return (
<View style={styles.container}>
<Button title="this is a test"
onPress={this.btnPress} />
</View>
);
}
}
Or use an arrow function which uses a lexical context for this:
export default class App extends React.Component {
btnPress = () => {
console.log("Fn Button pressed");
}
render() {
return (
<View style={styles.container}>
<Button title="this is a test"
onPress={this.btnPress} />
</View>
);
}
}

React native: Cannot add a child that doesn't have a YogaNode or parent node

Just started learning react-native,
I have created one separate file flexdemo.js and created component as below:
import React, { Component } from 'react';
import { View } from 'react-native';
export default class FlexibleViews extends Component {
render() {
return (
<View style={{ flex: 1 }}>
<View style={{ flex: 1, backgroundColor: "powderblue" }}> </View>
<View style={{ flex: 2, backgroundColor: "skyblue" }}> </View>
<View style={{ flex: 3, backgroundColor: "steelblue" }}> </View>
</View>
);
}
}
and App.js file is as below:
import React, { Component } from 'react';
import {
AppRegistry,
Platform,
StyleSheet,
Text,
View, Image
} from 'react-native';
// import Bananas from './src/banana';
// import LotsOfStyles from './src/styledemo'
import FlexibleViews from './src/flexdemo';
export default class App extends Component {
render() {
return (
// <Bananas name = "Tapan"/>
<View>
<FlexibleViews />
</View>
);
}
}
That gives me this error:
Now if I try to run the code by adding flexdemo.js code into App.js then everything works fine.
Changed The App.js like this:
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
export default class FlexDimensionsBasics extends Component {
render() {
return (
// Try removing the `flex: 1` on the parent View.
// The parent will not have dimensions, so the children can't expand.
// What if you add `height: 300` instead of `flex: 1`?
<View style={{flex: 1}}>
<View style={{flex: 1, backgroundColor: 'powderblue'}} />
<View style={{flex: 2, backgroundColor: 'skyblue'}} />
<View style={{flex: 3, backgroundColor: 'steelblue'}} />
</View>
);
}
}
Remove comments inside component.
I was able to reproduce the issue with the code you provided. The solution is twofold:
In your flexdemo.js file you should remove the whitespaces from within the <View> tags. They are considered as text, and text is only allowed inside a <Text> component. I'd recommend making your <View> tags self closing until they have some content, to stay away from this issue in the future, like so:
import React, { Component } from 'react';
import { View } from 'react-native';
export default class FlexibleViews extends Component {
render() {
return (
<View style={{ flex: 1 }}>
<View style={{ flex: 1, backgroundColor: 'powderblue' }} />
<View style={{ flex: 2, backgroundColor: 'skyblue' }} />
<View style={{ flex: 3, backgroundColor: 'steelblue' }} />
</View>
);
}
}
This will render your components but still be faulty, as you wont see anything on the screen.
To get your flexible shades of blue to appear you'll either have to add flex to the <View> component in your App.js file or(depending on what your next steps are, I guess) remove it and render your <FlexibleViews> as the root component, since it is basically a <View> component with some children anyway.
There can be several reasons for this issue. Here the three I have seen the most:
Comments might be the cause. But instead of removing comments make
them work:
In the return()-Part variables need to be wrapped in {} like
{this.state.foo} so wrapping the comments works fine...
return(
<Text> This works {/* it really does */}</Text>
);
...as long as they are not the first or last element in the return statement:
return(
{/* This fails */}
<Text> because the comment is in the beginning or end </Text>
{/* This also fails */}
);
Conditional rendering might be the cause. If myCheck is undefined or
an empty string this can fail:
const myCheck = ""; /* or const myCheck = undefined */
return(
{myCheck && <MyComponent />}
);
but adding double negation !! works:
const myCheck = ""; /* or const myCheck = undefined */
return(
{!!myCheck && <MyComponent />}
);
Whitespaces (or actually any strings) within a component can cause
this, if not in a <Text>-Component:
Text in a View for example:
/* This fails */
return(
<View>it really does</View>
);
But also the tiny space between two components:
/* <View>*Space*<Text> fails: */
return(
<View> <Text>it really does</Text> </View>
);
But works if in a newline:
return(
<View>
{/* This works */}
<Text>surpisingly it does</Text>
</View>
);
Unfortunately these pitfalls do not always lead to errors. Sometimes they work. I guess this depends on which of all those many tools/lybraries/components you use and their versions in your app.
I downgrade react native version, then I got a different error, basically what it was I had a simple string within a view, something like this:
<View>
MyComponent
</View>
I had to wrap the string with a text component like this:
<View>
<Text>MyComponent</Text>
</View>
hope that helps
This error is usually from one of below mistakes
Remove unnecessary comments and remove comments from return function.
check for proper variable name.
check for unintended semicolon or any wrong syntax
Delete the comment in the return block "// "
I encountered the same problem when I accidentally add a ';' in the return block, the iOS is work well, but the Android has this bug information
If you have if else statement in your render() function use !! like this:
{!! (this.state.your_state) &&
<View>
<Text>Your Text</Text>
</View>
}
instead of:
{(this.state.your_state) &&
<View>
<Text>Your Text</Text>
</View>
}

Resources