Render results on submit react native - javascript

New to react native. I want to render what is currently being logged in the console into a separate jsx Text elements, but I've been having trouble.
const handleSubmit = async () => {
const response = await fetch(
`http://127.0.0.1:5000/GetRecipes/${searchText}`,
{
method: "GET",
}
);
const result = await response.json();
const recipes = result["recs"];
for (var meal in recipes) {
if (recipes.hasOwnProperty(meal)) {
console.log(recipes[meal].meal); // want to display this
setSubmitPressed(submitPressed);
}
}
// want to render the results in text elements
const Test = () => {
return <Text>hi</Text>;
};
const DisplayRecipes = ({ recipes }) => {
return (
<View>
<Text>Meals</Text>
{recipes.map((ing) => (
<View key={ing[meal].meal}>
<Text>{ing[meal].meal}</Text>
</View>
))}
</View>
);
};
};
The results should only be displayed after a user submits input from a text input field and the results are fetched.
HandleSubmit is called in the onPress prop of a button.
The reference data looks like this
{0, {“meal”: “Chicken Wings”}}, {1, {“meal”: “Hamburger”}}

Please find below code:
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default function App() {
const recipes = [
{
"id": 0,
"meal": "ChickenWings"
},
{
"id": 1,
"meal": "Hamburger"
}
]
return (
<View style={styles.container}>
<Text>Meals</Text>
{recipes.map((ing) => (
<View key={ing.id}>
<Text>{ing.meal}</Text>
</View>
))}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
You can set your data as per requirement.

Related

How can I delete components one by one? [duplicate]

This question already has answers here:
How to delete an item from state array?
(18 answers)
Closed 2 years ago.
I'm currently developing an application using React Native.
This trial app has two buttons (ADD and DELETE).
When I press the ADD Button, a new component appears. If I press the DELETE Button that the same component disappears.
My question is: why can't I delete components one by one in this code?
even though I select an index of components I want to delete, all components disappear when I press a DELETE button...
How can I resolve this problem?
Here is the code (Screen):
import React, { useState } from "react";
import { ScrollView } from "react-native";
import Items from "../components/Items";
export default function Screen() {
const items = {
lists: [""],
};
const [stateItems, setStateItems] = useState(items);
return (
<ScrollView>
<Items stateItems={stateItems} setStateItems={setStateItems} />
</ScrollView>
);
}
Here is the code (Components):
import React from "react";
import { StyleSheet, View, Text, TouchableOpacity } from "react-native";
function Item({ index, handleAdd, handleDelete }) {
return (
<View style={styles.list}>
<TouchableOpacity
onPress={() => {
handleDelete(index);
}}
style={styles.buttonDelate}
>
<Text>DELETE</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
handleAdd();
}}
style={[styles.buttonDelate, styles.buttonAdd]}
>
<Text>ADD</Text>
</TouchableOpacity>
</View>
);
}
export default function Items(props) {
const stateItems = props.stateItems;
const setStateItems = props.setStateItems;
const handleAdd = () => {
setStateItems({
...stateItems,
lists: [...stateItems.lists, ""],
});
};
const handleDelete = (index) => {
const ret = stateItems.lists;
setStateItems({ ...ret, lists: [...ret].splice(index, 1) });
};
return (
<View>
{stateItems.lists.map((value, i) => (
<Item
key={value + i.toString()}
index={i}
stateItems={stateItems}
setStateItems={setStateItems}
handleAdd={handleAdd}
handleDelete={handleDelete}
/>
))}
</View>
);
}
const styles = StyleSheet.create({
list: {
width: "100%",
backgroundColor: "#ddd",
margin: 5,
padding: 10,
},
buttonDelate: {
backgroundColor: "tomato",
width: 80,
height: 40,
borderRadius: 5,
margin: 3,
justifyContent: "center",
alignItems: "center",
alignSelf: "center",
},
buttonAdd: {
backgroundColor: "orange",
},
});
node : 12.18.3
react native : 4.10.1
expo : 3.22.3
Splice returns the deleted items, not the original array. So when you do:
setStateItems({ ...ret, lists: [...ret].splice(index, 1) });
you're setting lists to the items deleted from [...ret], not the remaining ones.
We might also want to address why you're spreading the list into state and also setting lists to the deleted items from a copy of the original ret array.
const handleDelete = (index) => {
const ret = stateItems.lists;
setStateItems({ ...ret, lists: [...ret].splice(index, 1) });
};
The first part of this is stomping your other state with the lists array, which I highly doubt is what you want. Maybe you intended to preserve other state properties? Something more like:
const handleDelete = (index) => {
const { lists: old, ...others } = stateItems;
const lists = [...old];
lists.splice(index, 1);
setStateItems({ ...others, lists });
};

React Native Delete Function not working as intended

The intended function is that it would just delete the one goal that is clicked but for some odd reason it decides onPress to delete all goals listed.
I am following this tutorial https://www.youtube.com/watch?v=qSRrxpdMpVc and im stuck around 2:44:45. If anyone else has done this tutorial and or can see my problem an explanation would be greatly appreciated. :)
Program
import React, { useState } from "react";
import {
StyleSheet,
Text,
View,
Button,
TextInput,
ScrollView,
FlatList
} from "react-native";
import GoalItem from "./components/GoalItem";
import GoalInput from "./components/GoalInput";
export default function App() {
const [courseGoals, setCourseGoals] = useState([]);
const addGoalHandler = goalTitle => {
setCourseGoals(currentGoals => [
...currentGoals,
{ key: Math.random().toString(), value: goalTitle }
]);
};
const removeGoalHander = goalId => {
setCourseGoals(currentGoals => {
return currentGoals.filter((goal) => goal.id !== goalId);
});
};
return (
<View style={styles.screen}>
<GoalInput onAddGoal={addGoalHandler} />
<FlatList
keyExtractor={(item, index) => item.id}
data={courseGoals}
renderItem={itemData => (
<GoalItem
id={itemData.item.id}
onDelete={removeGoalHander}
title={itemData.item.value}
/>
)}
></FlatList>
</View>
);
}
const styles = StyleSheet.create({
screen: {
padding: 80
}
});
Function
import React from "react";
import { View, Text, StyleSheet, TouchableOpacity } from "react-native";
const GoalItem = props => {
return (
<TouchableOpacity onPress={props.onDelete.bind(this, props.id)}>
<View style={styles.listItem}>
<Text>{props.title}</Text>
</View>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
listItem: {
padding: 10,
backgroundColor: "lightgrey",
borderColor: "grey",
borderRadius: 5,
borderWidth: 1,
marginVertical: 10
}
});
export default GoalItem;
When updating state, you have to pass new array so component can detect changes and update view
const removeGoalHander = goalId => {
setCourseGoals(currentGoals => {
const newGoals = currentGoals.filter((goal) => goal.id !== goalId);
return [...newGoals];
});
};

React Native - Navigating two screen using two different fetch request

I'm new in react native. I'm creating a flatlist which contains a category buttons of foods, and once click a category button a second page will be display containing a kinds of foods depending on what category button the user clicks.
The names of the category button is load from my database, so I have a fetch for that. Now, as I've said I have to display a second page once a button is clicked.
I've already done a code where there is 2 kinds of fetch request for displaying my category name in the button and for navigating to the second page using the other fetch.
The problem is; once a category button is clicked, my button won't display any second page.
Here is my code
categories.js
import React, {Component} from 'react';
import {Text, TouchableHighlight, View,
StyleSheet, Platform, FlatList, AppRegistry,
TouchableOpacity
} from 'react-native';
var screen = Dimensions.get('window');*/
export default class Categories extends Component {
static navigationOptions = {
title: 'Product2'
};
state = {
data: [],
};
fetchData = async() => {
const response_Cat = await fetch('http://192.168.254.102:3307/Categories/');
const category_Cat = await response_Cat.json();
this.setState({data: category_Cat});
};
componentDidMount() {
this.fetchData();
};
FoodCat = async() => {
const { params } = this.props.navigation.navigate('state');
const response_Food = await fetch('http://192.168.254.102:3307/foods/' + params.id);
const food_Food = await response_Food.json();
this.setState({data: food_Food});
};
componentDidCatch() {
this.FoodCat();
};
render() {
const { navigate } = this.props.navigation;
const { params } = this.props.navigation.navigate('state');
return (
<View style = { styles.container }>
<FlatList
data = { this.state.data }
renderItem = {({ item }) =>
<TouchableOpacity style = {styles.buttonContainer}>
<Text style = {styles.buttonText}
onPress = { () => navigate('FoodCat', { id: item.id }) }>{ item.cat_name }</Text>
</TouchableOpacity>
}
keyExtractor={(x,i) => i}
/>
</View>
);
}
}
AppRegistry.registerComponent('Categories', () => Categories);
Details.js
import React, {Component} from 'react';
import { AppRegistry, StyleSheet,
FlatList, Text, View }
from 'react-native';
export default class Details extends Component {
constructor() {
super()
this.state = {
dataSource: []
}
}
renderItem = ({ item }) => {
return (
<View style = {{flex: 1, flexDirection: 'row'}}>
<View style = {{flex: 1, justifyContent: 'center'}}>
<Text>
{item.menu_desc}
</Text>
<Text>
{item.menu_price}
</Text>
</View>
</View>
)
}
componentDidMount() {
const url = 'http://192.168.254.102:3307/foods/'
fetch(url)
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
dataSource: responseJson.data
})
})
.catch((error) => {
console.log(error)
})
}
render(){
console.log(this.state.dataSource)
const { params } = this.props.navigation.navigate('state');
return (
<View style = { styles.container }>
<FlatList
data = { this.state.dataSource }
renderItem = {this.renderItem}
keyExtractor={(item, index) => index.toString()}
/>
</View>
);
}
}
AppRegistry.registerComponent('Details', () => Details);

React Native changing background color according to data that comes through http request from server

I am new at React Native.
I'm working on a code that will change the background color of a box (card) according to the data that I will get from API. I want to check first if the title is like 'Taylor' make background red , if it is 'Fearless' make it green and so on.
Here is the API that I got information from :
http://rallycoding.herokuapp.com/api/music_albums
This is the code divided into several files.
First of them index.js
// Import a library to help to create a component
import React from 'react';
import { Text, AppRegistry, View } from 'react-native';
import Header from './src/components/header.js';
import AlbumList from './src/components/AlbumList.js'
// create a component
const App = () => (
<View>
<Header headerText={'Smart Parking'}/>
<AlbumList />
</View>
);
//render it to the device
AppRegistry.registerComponent('albums2', () => App);
second is AlbumList.js
import React, { Component } from 'react';
import { View } from 'react-native';
import axios from 'axios';
import AlbumDetail from './AlbumDetail.js'
class AlbumList extends Component {
state = { albums: [] };
componentWillMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(response => this.setState({ albums: response.data }) );
}
renderAlbums() {
return this.state.albums.map(album =>
<AlbumDetail key={album.title} album={album} />
);
}
render() {
return(
<View>
{this.renderAlbums()}
</View>
);
}
}
export default AlbumList;
3rd is AlbumDetail.js
import React from 'react';
import {Text, View} from 'react-native';
import Card from './Card.js'
const AlbumDetail = (props) => {
return(
<Card>
<Text> {props.album.title} </Text>
</Card>
);
};
export default AlbumDetail;
4th is card which I need to change background of it
import React from 'react';
import { View } from 'react-native';
const Card = (props) => {
return (
<View style={styles.containerStyle}>
{props.children}
</View>
);
};
const styles = {
containerStyle:{
borderWidth: 1,
borderRadius: 2,
backgroundColor: '#ddd',
borderBottomWidth: 0,
shadowColor: '#000',
shadowOffset: {width: 0, height:2 },
shadowOpacity: 0.1,
shadowRadius: 2,
elevation: 1,
marginLeft: 5,
marginRight: 5,
marginTop: 10
}
};
export default Card;
last one is header
// Import libraries for making components
import React from 'react';
import { Text, View } from 'react-native';
// make a components
const Header = (props) => {
const { textStyle, viewStyle } = styles;
return(
<View style={viewStyle}>
<Text style={textStyle}>{props.headerText}</Text>
</View>
)
};
const styles ={
viewStyle:{
backgroundColor:'orange',
justifyContent: 'center',
alignItems: 'center',
height: 60,
},
textStyle: {
fontSize: 20
}
};
// make the component to the other part of the app
export default Header;
Basically you need to pass the title of the album as prop to the Card from the AlbumDetails component and then on each Card calculate the color to use and pass it in the style like this:
// AlbumDetails.js component
import React from 'react';
import {Text, View} from 'react-native';
import Card from './Card.js'
const AlbumDetail = (props) => {
return(
<Card title={props.album.title}>
<Text> {props.album.title} </Text>
</Card>
);
};
export default AlbumDetail;
// Card.js component
import React from "react";
import { View } from "react-native";
function calculateColor(title) {
let bgColor;
switch (title) {
case "Taylor":
bgColor = "red";
break;
case "Fearless":
bgColor = "green";
break;
default:
bgColor = "orange";
break;
}
return bgColor;
}
const Card = props => {
const { title } = props;
const backgroundColor = calculateColor(title);
return (
<View style={[styles.containerStyle, { backgroundColor: backgroundColor }]}>
{props.children}
</View>
);
};
const styles = {
containerStyle: {
borderWidth: 1,
borderRadius: 2,
backgroundColor: "#ddd",
borderBottomWidth: 0,
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 2,
elevation: 1,
marginLeft: 5,
marginRight: 5,
marginTop: 10
}
};
export default Card;
Something like this should work:
Change the AlbumDetail to conditionally render the Card.
const AlbumDetail = props => {
if (props.album.title === 'Taylor') {
return (
<Card style={{ backgroundColor: 'red' }}>
<Text>{props.album.title}</Text>
</Card>
);
} else {
return (
<Card style={{ backgroundColor: 'green' }}>
<Text>{props.album.title}</Text>
</Card>
);
}
};
Override the default style of the card using the passed style prop.
const Card = props => {
return (
<View style={[styles.containerStyle, props.style]}>{props.children}</View>
);
};
accepted answer is great just its a bad habit to do things in render.
i also not sure since every title has a color why wouldnt the server send this in the object props in first place ? :)
class AlbumList extends Component {
state = { albums: [] };
componentDidMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(response=> Array.isArray(response.data) ? response.data : []) // alittle validation would not hurt :) !
.then(data => this.setState({ albums: data }) );
}
selectHeaderColorForAlbum( album ){
let headerColor = 'red';
// switch(album.title){ ..you logic }
return headerColor;
}
renderAlbums() {
return this.state.albums.map(album =>
<AlbumDetail key={album.title} album={album} color={this.selectHeaderColorForAlbum(album)} />
);
}
render() {
return(
<View>
{this.renderAlbums()}
</View>
);
}
}
const Card = (props) => {
return (
<View style={[styles.containerStyle,{color:props.headerColor}]}>
{props.children}
</View>
);
};
this is easier your logic will render only once.
also notice that react >16.0 depricated componentWillMount, so use DidMount

React-native ListView with Navigation

I am trying to use component ListView with Navigation but I get undefined is not an object (evaluating'_this.props.navigator') error
My ListView is in Contacts.js
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, ListView, Text, View, Navigator } from 'react-native';
import Row from './Row'
import SearchBar from './SearchBar'
import Sections from './Sections'
import Load from './Load'
import demoData from './data'
import Pagination from '../Pagination';
export default class Contacts extends React.Component{
constructor(props) {
super(props)
const getSectionData = (dataBlob, sectionId) => dataBlob[sectionId];
const getRowData = (dataBlob, sectionId, rowId) => dataBlob[`${rowId}`];
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
sectionHeaderHasChanged : (s1, s2) => s1 !== s2,
getSectionData,
getRowData,
});
const { dataBlob, sectionIds, rowIds } = this.formatData(demoData);
// Init state
this.state = {
dataSource: ds.cloneWithRowsAndSections(dataBlob, sectionIds, rowIds),
left: true,
center: false,
right: false
}
}
formatData(data) {
// We're sorting by alphabetically so we need the alphabet
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
// Need somewhere to store our data
const dataBlob = {};
const sectionIds = [];
const rowIds = [];
// Each section is going to represent a letter in the alphabet so we loop over the alphabet
for (let sectionId = 0; sectionId < alphabet.length; sectionId++) {
// Get the character we're currently looking for
const currentChar = alphabet[sectionId];
// Get users whose first name starts with the current letter
const users = data.filter((user) => user.name.first.toUpperCase().indexOf(currentChar) === 0);
// If there are any users who have a first name starting with the current letter then we'll
// add a new section otherwise we just skip over it
if (users.length > 0) {
// Add a section id to our array so the listview knows that we've got a new section
sectionIds.push(sectionId);
// Store any data we would want to display in the section header. In our case we want to show
// the current character
dataBlob[sectionId] = { character: currentChar };
// Setup a new array that we can store the row ids for this section
rowIds.push([]);
// Loop over the valid users for this section
for (let i = 0; i < users.length; i++) {
// Create a unique row id for the data blob that the listview can use for reference
const rowId = `${sectionId}:${i}`;
// Push the row id to the row ids array. This is what listview will reference to pull
// data from our data blob
rowIds[rowIds.length - 1].push(rowId);
// Store the data we care about for this row
dataBlob[rowId] = users[i];
}
}
}
return { dataBlob, sectionIds, rowIds };
}
render() {
return (
<View style={styles.contactsContainer} >
<Pagination
left={this.state.left}
center={this.state.center}
right={this.state.right}
/>
<ListView
style={styles.listContainer}
dataSource={this.state.dataSource}
renderRow={(data) => <Row {...data} navigator={this.props.Navigator} />}
renderSeparator={(sectionId, rowId) => <View key={rowId} style={styles.separator} />}
renderHeader={() => <SearchBar />}
renderFooter={() => <Load />}
renderSectionHeader={(sectionData) => <Sections {...sectionData} />}
/>
</View>
);
}
}
const styles = StyleSheet.create({
contactsContainer: {
flex: 1
},
listContainer: {
marginTop: 10
},
separator: {
flex: 1,
height: StyleSheet.hairlineWidth,
backgroundColor: '#8E8E8E',
}
});
Line
renderRow={(data) => }
calls Row.js and prints contacts data
import React from 'react';
import ProfileScreen from './ProfileScreen'
import { AppRegistry, View, Text, StyleSheet, TouchableHighlight, Alert, Navigator } from 'react-native';
const Row = (props) => (
<TouchableHighlight onPress={() => this.props.Navigator.push({ screen: 'ProfileScreen' })} underlayColor="#FFFFFF">
<View style={ styles.container }>
<View style={ styles.status } />
<Text style={ styles.text }>
{`${ props.name.first } ${ props.name.last }`}
</Text>
</View>
</TouchableHighlight>
);
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 12,
flexDirection: 'row',
alignItems: 'center',
},
text: {
marginLeft: 12,
fontSize: 16,
},
status: {
backgroundColor: '#5cb85c',
height: 10,
width: 10,
borderRadius: 20,
},
});
export default Row;
As you can see each row has a TouchableHighlight when pressed it should navigate to ProfileScreen
EDIT
DO NOT USE NAVIGATOR IT IS DEPRECIATED INSTED USE STACKNAVIGATOR
There is no need to use this.props.Navigator when you are importing the Navigator module. Just use Navigator. this.props contains the list of all the attributes that you pass on to a component
Eg:
Parent.js
class Parent extends React.Component {
render() {
<Child firstProp={"FirstProp"} secondProps={"SecondProp"} />
}
}
Child.js
import {externalImport} from './externalFile'
class Child extends React.Component{
render() {
<div>
I AM FIRST PROP {this.props.firstProp}
I AM SECOND PROP {this.props.secondProp}
I AM NOT A PROP, JUST AN IMPORT { externalImport }
</div>
}
}

Categories

Resources