How do I use map in React Native to create separate buttons? - javascript

I'm trying to make a simple quiz app in React Native:
App.js
export default class App extends React.Component {
constructor(props) {
super(props);
this.quizData = [
{
question: 'Who wrote A Game Of Thrones?',
correctAnswer: 'George RR Martin',
possibleAnswers: ['JK Rowling', 'Phillip Pulman', 'George RR Martin' ]
},
];
}
render() {
return (
<View style={styles.container}>
<MultiChoice answers={this.quizData[0].possibleAnswers}/>
</View>
);
}
}
And my MultiChoice component:
import React, { Component } from 'react';
import { StyleSheet, Text, View } from 'react-native';
class MultiChoice extends Component {
render() {
return(
<View>
<Text style={styles.button}>{ this.props.answers.map(answer => answer) }</Text>
</View>
)
}
}
const styles = StyleSheet.create({
button: {
backgroundColor: 'blue',
width: 200,
height: 40,
}
})
export default MultiChoice;
I don't get any errors and all the elements of the array are displayed in the same button, but I would like to have three separate buttons. I wrote the same code in React and it worked, but in React Native it is not working.

Currently, your map just returns each element, unmodified -- it does nothing. It will then create one single <Text> component with all the text. Just have the map operation return a separate <Text> component for every element to achieve separate buttons:
{ this.props.answers.map(answer => <Text style={styles.button}>{answer}</Text>) }
And this will create separate <Text> components with the strings.

Related

How do I create a reusable component in react native? with this example

I managed to render the component for myself after so long trying, sorry I am new to react native, but I want to use the <DarkLight> component to cover everything inside and style the whole application and be able to continue using everything, as an example : when we use a <view>: we put in the middle another functional component like <Text> or another <View> you can use everything inside it and in turn its properties, I want to use <DarkLight> in the same way as if it were a <View > that encompasses the entire app Modifying the styles or properties and placing more components inside it, such as placing a <table> inside <DarkLight> (the table is also a component created to reuse) to be able to give it properties or styles also separately or if I create another component like the example of the <Table> put it inside <DarkLight> and keep it working .... in <DarkLight> I put a <Text> and it does nothing, this is what I mean ..., and I keep using all with props, I took this example from expo co lor-schemes, I would like to make it a reusable component that encompasses my entire application so that I am able to reuse it in another application. I want to learn how to build reusable components. I see props and components I do not want to advance without understanding well, being able to create a component that I can reuse. But I'm not sure if in these cases I should use state .. someone can help me and explain and I apologize for the inconvenience. :>
// App.js
import React from 'react';
import Home from './src/Home'
export default function App() {
return (
<Home/>
);
}
// Home.js
import React from 'react';
import { Text, StyleSheet, View, useColorScheme, Button } from 'react-native';
import DarkLight from '../src/Components/Dark_Light.js'
export default function Home() {
return (
<DarkLight>
<Text>Hello World</Text>
</DarkLight>
);
}
// Dark_Light.js
import React from 'react';
import { Text, StyleSheet, View, useColorScheme } from 'react-native';
import {globalStyles} from '../Styles/globalStyles'
const ThemeDark = (props) => {
const colorScheme = useColorScheme();
const themeTextStyle = colorScheme === 'light' ? globalStyles.lightThemeText : globalStyles.darkThemeText;
const themeContainerStyle = colorScheme === 'light' ? globalStyles.lightContainer : globalStyles.darkContainer;
const {children} = props;
return(
<View style={[globalStyles.container, themeContainerStyle]}>
<Text style={[globalStyles.text, themeTextStyle]}>
Color scheme: {colorScheme}
{children}
</Text>
{children}
</View>
)
}
export default function DarkLight() {
return (
<ThemeDark>
</ThemeDark>
);
}
// globalStyles.js // the global styles would like to be able to pass properties to it and modify it, what am I doing wrong? and what should i do?
import { StyleSheet } from "react-native";
export const globalStyles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
lightContainer: {
backgroundColor: '#d0d0c0',
},
darkContainer: {
backgroundColor: '#242c40',
},
lightThemeText: {
color: '#242c40',
},
darkThemeText: {
color: '#d0d0c0',
},
});

React.Native: Flat List not showing up

I am trying to return two things, a separate Mission component and a flat list. When I run my emulator, I can get the return on the Mission component but not the flat list. There are no errors, so I'm a bit lost with how to approach this issue. I even double-checked my imports. Here is the code:
import React, { Component } from "react";
import { ScrollView, Text, FlatList } from 'react-native';
import Mission from './Mission';
import PARTNERS from '../shared/partners';
import { ListItem } from 'react-native-elements';
class About extends Component {
constructor(props) {
super(props);
this.state = {
partners: PARTNERS,
}
};
static navigationOptions = {
title: 'About Us'
}
render() {
const { navigate } = this.props.navigation;
const renderPartner = ({ item }) => {
return (
<ListItem
title={item.name}
subtitle={item.description}
leftAvatar={{ source: require('./images/bootstrap-logo.png') }}
/>
);
};
return (
<ScrollView>
<Mission />
<FlatList
data={this.state.partners}
renderItem={renderPartner}
keyExtractor={item => item.id.toString()}
/>
</ScrollView >
);
}
}
export default About;
import React, { Component } from 'react';
import { FlatList, View, Text } from 'react-native';
import { ListItem, Card } from 'react-native-elements';
import { FILMS } from '../shared/films';
/*
When working correctly, when you hit "Tap to play" in the simulated mobile device to the right, you will see a list of films from shared/films.js.
Before updating this code:
- You must be logged into your Expo account (create an account if you do not have one already)
- Use the Save button on the upper right corner to fork this Snack to your account. Name it as you please, or accept the default random name.
Share the link to your version in the forum for this code challenge.
Your challenges: 1. Fix the component by adding a constructor and adding the data imported as FILMS to the component's state
2. In the FlatList, use that state data for films in the 'data' attribute.
3. In the ListItem, add the film title as the title, and the director as the subtitle.
4. Update films.js to add a third film of your choice.
Bonus Challenge: Write a custom view in the ListItem subtitle to show more details about each film, such as the release year, genre, language.
*/
class FilmCatalogue extends Component {
constructor(props) {
super(props);
this.state = {
films: FILMS
}
}
render() {
const renderFilm = ({item}) => {
return (
<ListItem
title={item.title}
titleStyle={{fontWeight: 700, color: 'dark-grey'}}
subtitle={
<View >
<Text style={{fontStyle: "italic", fontWeight: 500}}>{item.director}</Text>
<Text>{item.category}</Text>
<Text>{item.language}</Text>
</View>
}
rightSubtitle={item.year}
bottomDivider
/>
);
};
return (
<Card title="Film Catalogue">
<FlatList
data={this.state.films}
renderItem={renderFilm}
keyExtractor={item=>item.id.toString()}
/>
</Card>
);
}
}
export default FilmCatalogue;
i used this on an expo snack to display a list of the files i had in this file (the Film Catalogue Component.js)
hope this kind of helps!

I want to render dynamic content from back-end that has html tags in react native

I have created an app that uses woo-commerce as back-end, the problem is many of the attributes of products that I receive from back-end are in html, when I tried to render it in it treated everything as text and as a result the whole string got printed to the screen with all the html tags which is not the desired result .
Is there any trick except for the Web-View to solve this problem?
For me the best way to render HTML code is to use a library called react-native-htmlview.
This is a simple example:
import React, {Component} from 'react';
import {
View,
StyleSheet,
} from 'react-native';
import HTMLView from 'react-native-htmlview';
class App extends Component {
state = {
html: '<p>Some Dummy <b>HTML</b> code</p>'
}
render() {
return (
<View style={styles.container}>
<HTMLView
value={this.state.html}
stylesheet={htmlStyleSheet}
/>
</View>
);
}
}
const htmlStyleSheet = StyleSheet.create({
p: {
color: 'red'
},
b: {
color: 'black'
}
})
const styles = StyleSheet.create({
container: {
paddingTop: 20,
}
})
export default App;
For more information:
https://github.com/archriss/react-native-render-html
Another option is to use WebView with source prop:
https://facebook.github.io/react-native/docs/webview
import React, { Component } from 'react';
import { WebView } from 'react-native';
class MyInlineWeb extends Component {
render() {
return (
<WebView
originWhitelist={['*']}
source={{ html: '<h1>Hello world</h1>' }}
/>
);
}
}

The 'this' keyword in React Native refers to the great-grandchild of 'this' instead

Ok, I realise this code is smelly but just bear with me for a moment.
I was playing around with the code here and I have a strange situation wrt the this keyword.
In the code snippets that follow below, I want a button press in TopBar to trigger the goose method in index.ios.js, which it does. However, inside goose this refers to the great grandchild:
Child = ComponentOne
Grandchild = VoterScreen
Great-Grandchild = TopBar
Clearly, this is due to the way I'm passing the props down to the TopBar which I'm certain isn't the 'React Native way' but can anybody tell me either:
1 - How to adapt the code below and refer to this correctly (from what I've read that would make render be called again because of a change in state, eliminating the need to call forceUpdate()).
OR:
2 - How to enable the great-grandchild to call a goose where this is the this I expect by editing the way the callbacks are working.
The code for index.ios.js:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
View
} from 'react-native';
import VoterScreen from './components/voter-screen.js'
export default class StyleAB extends Component {
constructor(props)
{
super(props);
this.state =
{
componentSelected: 'One',
}
}
changeComponent = (component) =>{
this.setState({componentSelected: component});
}
goose(){
console.log('State before: ' + JSON.stringify(this.state));
this.state = { componentSelected: 'Two', }
console.log('State after: ' + JSON.stringify(this.state));
this.forceUpdate();
}
renderComponent(component) {
if(component == 'One') {
return <ComponentOne changeComponent={this.changeComponent} goose={this.goose} />
} else if(component == 'Two') {
return <ComponentTwo changeComponent={this.changeComponent} />
} else if(component == 'Three') {
return <ComponentThree changeComponent={this.changeComponent} />
}
}
render() {
console.log('Render is called');
return (
<View style={styles.container}>
{this.renderComponent(this.state.componentSelected)}
</View>
);
}
}
class ComponentOne extends Component {
render() {
return (
<VoterScreen sendData={this.props.goose}/>
)
}
}
class ComponentTwo extends Component {
render() {
return (
<UploadScreen/>
)
}
}
class ComponentThree extends Component {
render() {
return (
<ResultsScreen/>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
}
});
AppRegistry.registerComponent('StyleAB', () => StyleAB);
The code for voter-screen.js:
import React, { Component } from 'react';
import { View } from 'react-native';
import { Button } from 'react-native-elements';
import TopBar from './top-bar.js'
class VoterScreen extends Component {
render() {
console.log('Render is called in VoterScreen');
let topIsA = true;
return (
<View style={{flex: 1}}>
<TopBar parentToggle={this.props.sendData}/>
</View>
);
}
}
export default VoterScreen
The code for top-bar.js:
import React, { Component } from 'react'
import { View } from 'react-native';
import { Button } from 'react-native-elements';
class TopBar extends Component {
render() {
console.log('Render is called in TopBar');
return (
<View style={{flex: 1, flexDirection: 'row', backgroundColor: 'black'}}>
<Button
raised
containerViewStyle={{backgroundColor: 'black'}}
icon={{name: 'camera', type: 'font-awesome', size: 20, style: {marginRight: 0, textAlign: 'center'}}}
buttonStyle={{backgroundColor: '#cd00cd', borderRadius: 10, width: 50, height: 50}}
onPress={this.props.parentToggle.bind(this)}
/>
</View>
)
}
}
export default TopBar
EDIT:
The answer was to do 3 things:
1 - In index.ios.js:
Change:
return <ComponentOne changeComponent={this.changeComponent} goose={this.goose} />
To:
return <ComponentOne changeComponent={this.changeComponent} goose={this.goose.bind(this)} />
2 - in the same file:
Change:
<VoterScreen sendData={this.props.goose}/>
To:
<VoterScreen sendData={this.props.goose.bind(this)}/> [Thanks Chris].
3 - In top-bar.js:
Change:
onPress={this.props.parentToggle.bind(this)}
To:
onPress={this.props.parentToggle} [Thanks Eduard].
Try binding the scope before passing it down like this...
<VoterScreen sendData={this.props.goose.bind(this)}/>
If you want this to refer to the parent component, why do you bind it in the great grandchild?
Have you tried going this way?
onPress={this.props.parentToggle}
or this:
onPress={() => this.props.parentToggle}
Not sure if I read what you're asking correctly but changing goose(){ to goose = () => { should fix all your issues. Also it's not good for performance to bind in render so you might want to create another method on each component you want to bind or bind in the constructor.

Route should declare a screen. [ React Native Navigation Error]

Hi I am new to react native and I am facing strange issue with routing. I am doing something wrong but need someone to guide me.
index.android.js
import { LandingScreen } from './src/components/landing_screen.js'
import HomeScreen from './src/app_component.js'
import { StackNavigator } from 'react-navigation';
const SimpleApp = StackNavigator({
Home: { screen: HomeScreen },
Landing: { screen: LandingScreen},
});
AppRegistry.registerComponent('HomeScreen', () => SimpleApp);
app_component.js
// Other imports ...
export default class HomeScreen extends Component {
static navigationOptions = {
title: 'Home Screen',
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}> Hello CHannoo!!!</Text>
<Text style={styles.instructions}>
To get started, edit index.android.js
</Text>
<Text style={styles.instructions}>
Double tap R on your keyboard to reload,{'\n'}
Shake or press menu button for dev menu
</Text>
<Button
title="Go to 2nd Page"
onPress={() =>
// alert('hello');
navigate('LandingScreen')
// navigate('Home', { name: 'Jane' })
}
/>
</View>
);
}
componentDidMount () {
SplashScreen.close({
animationType: SplashScreen.animationType.scale,
duration: 850,
delay: 500,
})
}
}
landing_screen.js
export default class LandingScreen extends Component {
static navigationOptions = {
title: 'Landing Screen Title',
};
render() {
return (........)
}
It works fine if we remove route Landing. But when we add this route we get error.
Route 'Landing' should declare a screen. For example ......
Your LandingScreen has been exported as default but you imported it by name.
your import statement is like this:
import { LandingScreen } from './src/components/landing_screen.js'
replace it with line below (without curly brackets):
import LandingScreen from './src/components/landing_screen.js'
it should solve the problem.
BUT you will probably get a new error as #Medet pointed out because you have to change this line:
navigate('LandingScreen')
to:
navigate('Landing')
since your screen name is Landing.
You calling navigate('LandingScreen')
But screen name is Landing
+ #Dusk's answer should solve

Categories

Resources