MainPage
export class Diet extends Component {
constructor(props) {
super(props);
this.state = {
list: [],
};
}
addToList(item) {
const list = [...this.state.list, item];
this.setState({ list });
}
render() {
return (
<View>
<Text style={styles.txtYourMeals}>Your Meals</Text>
<FoodList items={this.state.list} /> <--------
</View>
);
}
}
export default Diet;
FoodList
import React, { Component } from "react";
export class FoodList extends Component {
render() {
return (
<View>
<Content>
<List>
<ListItem>
<Text>FoodCreated</Text>
</ListItem>
</List>
</Content>
</View>
);
}
}
export default FoodList;
FoodCreate
export default function FoodCreate({ navigation: { goBack } }) {
const [FoodName, setFoodName] = useState("");
return (
<Container>
<Header>
<Left>
<Button transparent>
<Icon
name="arrow-back"
onPress={() => goBack()}
style={{ fontSize: 25, color: "red" }}
/>
</Button>
</Left>
<Body>
<Title>Add Food</Title>
</Body>
<Right>
<Button transparent>
<Icon <-----------
name="checkmark"
style={{ fontSize: 25, color: "red" }}/>
</Button>
</Right>
</Header>
<TextInput
placeholder="Food Name"
placeholderTextColor="white"
style={styles.inptFood}
value={FoodName}
onChangeText={(FoodName) => setFoodName(FoodName)}
/>
</Container>
);
}
So I'm trying to let the user type a Food Name in a TextInput in the FoodCreate page and pressing the button checkmark to add that food name in the FoodList which is displayed in the MainPage. I started but I have no idea on how to proceed. It's a basic grocery shopping list in which you type a food name and add it to your list and every time you do that you insert a new item.
What you need is to tell the parent component i.e. MainPage that a new food item has been created.
This should look something like this in your MainPage
render() {
return (
<>
<FoodCreate addToList={addToList}/>
<View>
<Text style={styles.txtYourMeals}>Your Meals</Text>
<FoodList items={this.state.list} /> <--------
</View>
);
}
Now, this addToList would be available to your FoodCreate component which you can call whenever you create the food item. Also, I don't see any Save button in your FoodCreate. I think that's where you might want to add a click listener so that whenever user clicks on that button, you call the addToList method
Related
I saw dozens of examples but they are not working in my case, I want to update the page variable in "bookitem" component and rerender it. using gives an error ' Expected an assignment or function call and instead saw an expression no-unused-expressions'
import React from 'react'
import { Pagination, Container } from 'semantic-ui-react'
import bookitem from './Book_item'
const PaginationI = () => (
<Container style={{textAlign: "center", padding:'4rem'}}>
<Pagination defaultActivePage={5} totalPages={10} onPageChange={PageChange}/>
</Container>
)
function PageChange(event,data){
console.log(data.activePage);
<bookitem page={data.activePage}/>
};
export default PaginationI
//////////////////////////////////////////////////////////////////////////////////////////////////////
class bookitem extends Component{
constructor(props){
super (props);
this.state={
counter:0,
page:0,
data2:[]
};
}
componentWillMount(){
console.log(this.props.page)
axios.get('/books/'+this.state.page).then(res=>{console.log(res.data);this.setState({data2:res.data});})
console.log('aa')
console.log(this.state.data2)
}
genurl(isbn){
console.log(isbn)
let url='http://covers.openlibrary.org/b/isbn/'+ isbn + '-L.jpg'
return url;
}
render(){return(
<div>
<div>{this.state.page}</div>
<Container>
<div style={{padding:"1em 1em", textAlign: "right"}}>
<Card.Group itemsPerRow={3} stackable={true} doubling={true}>
{this.state.data2.map(card=>(
<Card href="#">
<Image src={this.genurl(card.isbn)} wrapped ui={false} />
<Card.Content>
<Card.Header>{card.title}</Card.Header>
<Card.Meta>
<span className='date'>Author:{card.author}</span>
</Card.Meta>
<Card.Content >
<Rating icon='star' defaultRating={card.avgrating} maxRating={5} />
</Card.Content>
<Card.Description>
{card.avgrating} Avg rating, {card.totalratings} total ratings.
</Card.Description>
</Card.Content>
<Card.Content >
<a>
<Icon name='pencil alternate' />
{card.reviews} Reviews
</a>
</Card.Content>
</Card>
))}
</Card.Group>
</div>
</Container>
</div>
)
}
}
export default bookitem
The problem is that you are not rendering the bookitem component at all. You have to manage the state of your activePage, pass it to the bookitem and actually render this component.
import React, { useState } from "react";
import { Pagination, Container } from "semantic-ui-react";
import BookItem from "./Book_item";
const PaginationI = () => {
const [activePage, setActivePage] = useState(0); // manage the state of activePage
function PageChange(event, data) {
setActivePage(data.activePage); // update the state in event handler
}
return (
<Container style={{ textAlign: "center", padding: "4rem" }}>
<BookItem page={activePage} /> {/* render your component */}
<Pagination
defaultActivePage={5}
totalPages={10}
onPageChange={PageChange} /> {/* pass event handler */}
</Container>
);
};
export default PaginationI;
Also you would have to rename the bookitem component due to collision with HTML tags like this
import React from "react";
class BookItem extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0,
page: 0,
data2: [],
};
}
componentWillMount() {
console.log(this.props.page);
axios.get("/books/" + this.state.page).then((res) => {
console.log(res.data);
this.setState({ data2: res.data });
});
console.log("aa");
console.log(this.state.data2);
}
genurl(isbn) {
console.log(isbn);
let url = "http://covers.openlibrary.org/b/isbn/" + isbn + "-L.jpg";
return url;
}
render() {
return (
<div>
<div>{this.state.page}</div>
<Container>
<div style={{ padding: "1em 1em", textAlign: "right" }}>
<Card.Group itemsPerRow={3} stackable={true} doubling={true}>
{this.state.data2.map((card) => (
<Card href="#">
<Image src={this.genurl(card.isbn)} wrapped ui={false} />
<Card.Content>
<Card.Header>{card.title}</Card.Header>
<Card.Meta>
<span className="date">Author:{card.author}</span>
</Card.Meta>
<Card.Content>
<Rating
icon="star"
defaultRating={card.avgrating}
maxRating={5}
/>
</Card.Content>
<Card.Description>
{card.avgrating} Avg rating, {card.totalratings} total
ratings.
</Card.Description>
</Card.Content>
<Card.Content>
<a>
<Icon name="pencil alternate" />
{card.reviews} Reviews
</a>
</Card.Content>
</Card>
))}
</Card.Group>
</div>
</Container>
</div>
);
}
}
export default BookItem;
First of all Bookitem must starts with capitalized letter. So instead of <bookitem /> you must have <Bookitem/>.
Now if you want to change state of a react component from another component, you have to pass a function from parent to child which will be called when you want to change the state. For example
const Compoent1 = () => {
const [state, setState] = useState(value)
.....
return <Component2 changeState={setState} />
}
Hey there so i'm new to react native and javascript and currently i'm learning to make a custom radio button with images it looks like this my custom radio button in this page user is going to pick one button from the list, and i want to make it when the page first render it will show one pressed button and user is only allowed to pick one button. Can anyone tell me how to figure this out? Thanks in advance
here are my codes
RadioButton.js
export default class RadioButton extends Component {
constructor(props) {
super(props);
this.state = {
selected: this.props.currentSelection === this.props.value,
}
}
button() {
var imgSource = this.state.selected? this.props.normalImg : this.props.selectedImg;
return (
<Image
source={ imgSource }
/>
);
}
render() {
let activeButton = this.props.activeStyle ? this.props.activeStyle : styles.activeButton;
return (
<View style={[styles.container, this.props.containerStyle, this.state.selected || this.props.normalImg ? activeButton : inactiveButton]}>
<TouchableOpacity onPress={() => {
this.setState({ selected: !this.state.selected });
}}>
{
this.button()
}
</TouchableOpacity>
</View>
);
}
}
ActivityLog.js
class ActivityLog extends Component {
constructor(props){
super(props);
}
render() {
return (
<View style={styles.innerContainer}>
<Text style={styles.dialogText}>{`Log my activity at ${time} as...`}</Text>
<View style={styles.buttonContainer}>
<RadioButton selectedImg={img.activity.breakA} normalImg={img.activity.break} containerStyle={{marginHorizontal: normalize(10)}}/>
<RadioButton selectedImg={img.activity.meetingA} normalImg={img.activity.meeting} containerStyle={{marginHorizontal: normalize(10)}}/>
</View>
<View style={styles.buttonContainer}>
<RadioButton selectedImg={img.activity.otwA} normalImg={img.activity.otw} containerStyle={{marginHorizontal: normalize(10)}}/>
<RadioButton selectedImg={img.activity.officeA} normalImg={img.activity.office} containerStyle={{marginHorizontal: normalize(10)}}/>
</View>
);
}
}
Extract the activeStatus to ActivityLog so as to track which button is selected,right now you are maintaing a state for every button as a local state.So it is difficult to know other components to know about the button's active status.
Here is a generic implementation for rough idea.
const Child=(props)=>{
<TouchableOpacity onPress={props.handlePress}>
<Text style={[baseStyle,active && activeStyle]}>{props.title}</Text>
</TouchableOpacity>
}
class Parent extends React.Component{
state={
selectedChild:''
}
changeSelection=(sometitle)=>{
this.setState({
selectedChild:sometitle
})
}
render(){
return(
<View>
<Child handlePress={()=>this.changeSelection('1')} active={this.state.selectedChild==='1'}/>
<Child handlePress={()=>this.changeSelection('2')} active={this.state.selectedChild==='2'}/>
<Child handlePress={()=>this.changeSelection('3')} active={this.state.selectedChild==='3'}/>
<Child handlePress={()=>this.changeSelection('4')} active={this.state.selectedChild==='4'}/>
</View>
)
}
}
Expo demo Link
In header I add left component - icon, and I want to set icon on click. How can I do that?
I tried to set state value and return component that depends from this value.
<Header
placement="left"
leftComponent={
<Icon
name='keyboard-arrow-left'
color='#ffffff'
size={40}
onPress={}
/>
}
centerComponent={<Text>User Info</Text>}
/>
You can create separate component for icon
export class MyIcon extends Component {
state = { name: 'keyboard-arrow-left' }
render() {
return (
<Icon
name={this.state.name}
color='#ffffff'
size={40}
onPress={() => this.setState({ name: 'close' })}
/>
);
}
}
and use this component for leftComponent of your Header
<Header
placement="left"
leftComponent={
<MyIcon/>
}
centerComponent={<Text>User Info</Text>}
/>
The simplest way to fix this issue is to add a reference to your Icon component. Then use that reference to change any of the props of your icon.
constructor(props){
super(props);
this.state = {};
this.myIcon = '';
}
updateIconName = (nameEntered) => {
this.myIcon.name = nameEntered;
}
render() {
return(
<View style={{flex: 1}}>
<Header
placement="left"
leftComponent={
<Icon
name='keyboard-arrow-left'
color='#ffffff'
size={40}
onPress={this.updateIconName}
ref={(element) => {this.myIcon = element;}}
/>
}
centerComponent={<Text>User Info</Text>}
/>
</View>
);
}
I'm using react native List to generate a Dynamic list using a custom data array and in the ListItem. I am using nested checkbox in every list item and I can't set the switch. I tried it by setting array of state but it doesn't seem to work.
This is my list
const DashboardList = props => (
<List
style={props.ListStyle}
dataArray={props.ListData}
renderRow={item => <ListContent ListData={item} />}
/>
);
This is my listItem
class ListContent extends Component {
static navigationOptions = {
title: "ListContent",
header: null
};
constructor(props) {
super(props);
this.state = {
IsContentVisible: false
};
}
render() {
return (<ListItem>
<View>
<View>
<Left>
<View>
<CheckBox
checked={this.state.checked}
onPress={checked => {
this.setState({ checked: !this.state.checked });
this.props.CheckBoxChange(this.props.ListItem,
checked);}}/>
</View>
<View>
<Image
source={this.props.ListItem.DataFolderContent[0].Image}
resizeMethod="auto"
resizeMode="contain"
/>
</View>
<View>
<Text>
{this.props.ListItem.Name}
</Text>
</View>
</Left>
<Body>
<View>
<Badge style={{ backgroundColor: "#eeae30" }}>
<Text>{this.props.ListItem.DataFolderContent.length}
</Text>
</Badge>
</View>
</Body>
<Right >
<Switch
onTintColor="#eeae30"
value={this.state.switched}
onValueChange={() => {
this.setState({ switched: !this.state.switched });
this.props.SwitchToggled(this.props.ListItem);
}}
/>
</Right>
</View>
</View>
</ListItem>;
}
}
I have started learning react native 2 days back only. I am using list item component from Native Base UI framework.
According to their docs and examples to catch a click event on ListItem you need to add onPress and button option to the ListItem. But in my case its not working.
I have another element with also tracks click event, it works fine, but list element isn't catching click event.
Strange this is that if I trigger a alert, it works
<List button onPress={() => { Alert.alert('Item got clicked!') } }>
Below id my complete code
import React from 'react';
import {
Content,
List,
ListItem,
Body,
Thumbnail,
Text,
Badge,
View
} from 'native-base';
import { ActivityIndicator, TouchableHighlight, TouchableOpacity, Alert } from 'react-native';
export default class Questions extends React.Component{
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
Alert.alert("I am clicked");
// Call method from parent
this.props.onPress();
}
render() {
var items = this.props.items;
return (
<Content>
<List button onPress={() => { this.handleClick } }>
{Object.keys(items).map(function(eachQuestion) {
return (
<ListItem avatar key={items[eachQuestion].id} button onPress={() => { this.handleClick } } >
<Body>
<Text>{items[eachQuestion].question}</Text>
</Body>
</ListItem>
)
})}
</List>
<TouchableOpacity onPress={this.handleClick}>
<View><Text>Click me</Text></View>
</TouchableOpacity>
</Content>
);
}
}
Edit 1
render() {
var questions = {
"1" : "James",
"2" : "Smith",
"3" : "Doe",
"4" : "Smith"
};
return (
<Container>
<Content>
<List>
{Object.keys(questions).map(function(key) {
return (<ListItem button={true} onPress={this.handleClick}>
<Text>{questions[key]}</Text>
</ListItem>
)
})}
</List>
</Content>
</Container>
);
}
** Final Solution **
handleClick(){
Alert.alert("I got clicked");
}
render() {
var questions = this.props.questions;
return (
<Content>
<List>
{Object.keys(questions).map((eachQuestion) => {
return (
<ListItem key={questions[eachQuestion].id} button={true} onPress={this.handleClick} >
<Body>
<Text>{questions[eachQuestion].question}</Text>
</Body>
</ListItem>
)
})}
</List>
</Content>
);
}
Two errors:
You should brush up on your ES6 arrow function expressions. You aren't calling your handleClick function which is why nothing is happening vs your Alert example where it does work (since you are actually doing something).
You don't define the value for the button prop. The docs say that there is no default value, so it's good practice to define it as true or false.
So to fix your code, you should define your props for ListItem like so:
button={true}
onPress={() => { this.handleClick() }}
OR to make it shorter:
button={true}
onPress={this.handleClick}
I'm also not sure why you are defining button and onPress props on your List component since it's the ListItems that you are trying to click, not the entire List itself. But since that isn't part of the question, I won't address that.
Full example of working code:
import React, { Component } from 'react';
import { Container, Content, List, ListItem, Text } from 'native-base';
import { Alert } from 'react-native';
export default class App extends Component {
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
Alert.alert("I am clicked");
// Call method from parent
//this.props.onPress();
}
render() {
return (
<Container>
<Content>
<List>
<ListItem button={true} onPress={this.handleClick}>
<Text>Simon Mignolet</Text>
</ListItem>
<ListItem button={true} onPress={() => { this.handleClick() }}>
<Text>Nathaniel Clyne</Text>
</ListItem>
<ListItem button={true} onPress={this.handleClick}>
<Text>Dejan Lovren</Text>
</ListItem>
</List>
</Content>
</Container>
);
}
}