I'm running in an issue with React-Native. I have a FlatList where each item contains user's picture (30x30), user's name and a checkbox. These elements are wrapped in a TouchableHighlight:
handleClick = (item, index) => {
console.log(item);
console.log(index);
}
render() {
return (
<FlatList
data={datas}
renderItem={({item, index}) => this.renderUserItem(item, index)}
/>
);
}
renderUserItem(item, index) {
return (
<TouchableHighlight onPress={() => this.handleClick(this, index)}>
<View>
<Image source={{uri: 'https://randomuser.me/api/portraits/women/68.jpg'}}/>
<Text>{item.name}</Text>
<CheckboxComponent/>
</View>
</TouchableHighlight>
);
}
What I'm trying to do is if users click on the large TouchableHighlight (not only the CheckboxComponent), the CheckboxComponent gets "checked" or not. How can I access to CheckboxComponent in the list? Should I use ref? If yes, could you please provide an example working with a list?
Thanks,
Ugo
to keep state of CheckboxComponent you should use state not ref
you can do this
in constructor:
constructor(props) {
super(props);
this.state = {
activeCheckbox: null
}
}
in renderUserItem:
<CheckboxComponent checked={this.sate.activeCheckbox === index} />
(as you know CheckboxComponent must have checked prop)
in handleClick:
handleClick = (item, index) => {
this.setState({ activeCheckbox: index });
}
Related
I use react-native-elements library.
in ListItem Accordion there is onPress option to expand and unexpand list items.
but when I press one item, all of items expand!
screen shot 1
here is part of my code:
export class MyList extends Component {
state= {
expanded:false,
};
constructor(props) {
super(props);
this.state = {
expanded:false
};
}
handleToggle=()=>{
const {expanded}=this.state;
if(expanded){
this.setState({expanded:false});
}else{
this.setState({expanded:true})
}
}
render() {
return (
...
<View>
{list.map((l, i) => (
<ListItem.Accordion key={i}
content={
<>
<ListItem.Content>
<ListItem.Title>{l.name}</ListItem.Title>
<Avatar title={l.name[0]} source={{ uri: l.avatar_url }} />
</ListItem.Content>
</>
}
isExpanded={this.state.expanded}
onPress={this.handleToggle}
>
<ListItem key={i} bottomDivider>
<ListItem.Content>
<ListItem.Subtitle>{l.city}</ListItem.Subtitle>
<View style={styles.subtitleView}>
<Image source={require('../Images/4.5_stars.svg.png')} style={styles.ratingImage}/>
<Text style={styles.ratingText}>5 votes</Text>
</View>
</ListItem.Content>
<ListItem.Chevron />
</ListItem>
</ListItem.Accordion>
))}
...
is it my props problem?? if yes, how can I pass the item for each "onPress"??
Surely you already solved your problem.
I had the same problem and I solved it myself since I couldn't find a solution.
It turns out that it was very simple and probably arises from not being used to the React way of working.
A component must be created for your custom <ListItem.Accordion>,
then you get something like
{Turneras ? (Turneras.map((Turnera, i) => (
<ItemAccordion Turnera={Turnera} ></ItemAccordion>
))) : null
}
As easy as that, since each component will have its state expanded and it works perfectly.
I'm trying to take a user inputted code and compare it to code within my database. Right now I can bring the code and display it outside the map function but when I try to add it, it doesn't work. here is my database:
[
{
"dwelling_code": "ABC-XYZ",
"dwelling_name": "Neves Abode",
"has_superAdmin": true,
"room": []
}
This is the parent component:
class Dwel2 extends Component {
state = {
house: [],
selectedMovie: null,
data: "ABC-XYZ"
}
componentDidMount() {
fetch('Removed for question', {
method: 'GET',
headers: {
}
}).then(resp => resp.json())
.then(resp => this.setState({ house: resp }))
.catch(error => console.log(error))
}
houseClicked = h => {
console.log(h)
}
render() {
return <div>
<EnterCode dataFromParent={this.state.data}
house={this.state.house}
houseClicked={this.house} />
</div>
}
}
This is the child component:
function EnterCode(props) {
return (
<div>
<div>
*THIS BIT DISPLAYS THE CODE*{props.dataFromParent}
</div>
{props.house.map(house => {
var test = house.dwelling_name
var code = house.dwelling_code
if (code === {props.dataFromParent}) {
test = "Test"
}
return (
<React.Fragment>
<div>{test}</div>
</React.Fragment>
)
})}
</div>
)
}
I just want to compare the code in the database to the code defined in the parent component. Here is the error that's coming up this is in the child component.
Line 17:31: 'dataFromParent' is not defined no-undef
You made a tiny mistake in the if statement. You put the props.dataFromParent in brackets, which in the context of JSX would be required, but in the context of JS means creating an object, which is clearly wrong.
if (code === props.dataFromParent) {
test = "Test"
}
Hope this helps :)
I am working in demo Application for learning React native And I need to render clickable FlatList item.
Here is Render and itemClick function:
render() {
return (
<View style={styles.container}>
<View>
<FlatListData list={this.state.itemList} />
</View>
</View>
);
}
itemClick(item){
console.log('click on item', item);
}
I have already declare FlatListData functional component for that :
const FlatListData = ({list}) => {
return (
<FlatList
data={list}
keyExtractor={(item, index) => index.toString()}
renderItem={itemList}
/>
);
};
In FlatList component, RenderItem attribute have again custom component for single item i.e :
const itemList = ({item, index}) => {
return (
<TouchableOpacity onPress={this.itemClick(item)} style={styles.catalogContainer}>
<Image
source={{uri: item.img}}
style={styles.imageStyle}
/>
</TouchableOpacity>
);
};
But this code is not working. It will give me error like : Undefined is not an object (eveluting _this.itemClick)
Here in which way and where Should I write click function for item ?
Any one have a answer that can solve my problem ?
NOTE :
All code is written in one js file. My Render function is inside my class component. and other two declarative component are out of that class component.
I need that item inside that click function. But I don't know how to pass parameter inside function.
There are a couple of things you can do to fix your problem.
You need to move your itemClick function inside itemList as an arrow function.
const itemList = ({ item, index }) => {
itemClick = item => {
console.log("click on item", item);
};
return (
<TouchableOpacity
// onPress={this.itemClick(item)}
onPress={() => this.itemClick(item)}
style={styles.catalogContainer}
>
<Image source={{ uri: item.img }} style={styles.imageStyle} />
</TouchableOpacity>
);
};
Pass your itemClick function as props to child component
render() {
return (
<View style={styles.container}>
<FlatListData list={this.state.itemList} onItemClick={this.itemClick} />
</View>
);
}
itemClick = (item) => {
console.log('click on item', item);
}
Now you can call onItemClick prop inside itemList
const FlatListData = ({ list, onItemClick }) => {
itemList = ({ item }) => (
<TouchableOpacity
onPress={() => onItemClick(item)}
style={styles.catalogContainer}
>
<Image source={{ uri: item.img }} style={styles.imageStyle} />
</TouchableOpacity>
);
return (
<FlatList
data={list}
keyExtractor={(item, index) => index.toString()}
renderItem={this.itemList}
/>
);
};
Hope this helps you. Feel free for doubts.
Is it possible to use a Modal without a trigger? I will open and close it via state.
For example, I want to use onClick on an input field(with a file name) to open the modal with a file chooser and then edit the name of the choosen file in the input field. All this in a nested modal...
Looks much simpler if I will have both modals in a parent component without the triggers, and I will display/hide them via open={true/false}
Thanks
Yes it is. Don't set the prop trigger (it is not required) and just provide the open value from state/props.
class container extends Component {
state = {
isParentOpen: false,
isChildOpen: false
}
handleClick = () => {
this.setState({
isParentOpen: !this.state.isOpen
});
}
handleFocus = () => {
this.setState({
isChildOpen: true
});
}
render() {
return (
<div>
<Modal
open={this.state.isParentOpen}
size="large"
>
...
<Input onFocus={this.handleFocus} />
</Modal>
<Modal
open={this.state.isChildOpen}
size="small"
>
...
</Modal>
<Button onClick={this.handleClick} />
</div>
);
}
}
(You can nest Modal if you want to)
Pass a prop to the modal component and fire handleOpen according to the prop on ComponentDidMount. This will allow the modal to be closed.
class ModalContainer extends Component {
componentDidMount() {
const { startOpen } = this.props;
if (startOpen) {
this.handleOpen();
}
}
handleOpen = () => this.setState({ modalOpen: true });
handleClose = () => this.setState({ modalOpen: false });
render() {
return (
<Modal open={this.state.modalOpen} onClose={this.handleClose} />
)
}
I am new to RN, and I am trying to show/hide an item in a List based on logged user state.
I have achieved the goal to hide the item on logout, but still have problem on the login part.
I am using react-native-elements and especially the SideMenu component.
I have created two arrays as you can see below.
Here is my arrays:
var listLogged = [
{
name : 'Page 1'
},
{
name : 'Page 2'
},
{
name : 'Logout'
}];
var listNotLogged = [
{
name : 'Page 1'
},
{
name : 'Page 2'
}];
In the render:
if (this.state.LoggedIn) {
<List>
{
listLogged.map((item, j) => (
<ListItem
key={j}
title={item.name}
/>
))
}
</List>
} else {
<List>
{
listNotLogged.map((item, j) => (
<ListItem
key={j}
title={item.name}
/>
))
}
</List>
But unfortunately I do not know how and where set the state, the main problem is that the Menu component is already rendered before the login.
Hope in some help! Thank you in advance
If your <List /> component is inside of a React Component, you can use this.setState({ LoggedIn: true }) to change the state, and the render() function will automatically re-run.
I've whipped up an example below to show you how tapping a "Log In" button can change the state, which causes render() to re-run with the new state and produce a different outcome. Tapping Logout will toggle the state back:
import React, { Component } from 'react';
import { List, ListItem, SideMenu, Button } from 'react-native-elements';
const list = [
{ name: 'Page 1', onPress: null },
{ name: 'Page 2', onPress: null }
];
class Example extends Component {
constructor(props) {
super(props);
this.state = { LoggedIn: false };
}
toggleLoggedInState = () => {
this.setState({ LoggedIn: !this.state.LoggedIn });
}
render() {
let button;
if (this.state.LoggedIn) {
list.push({ name: 'Logout', onPress: this.toggleLoggedInState });
button = <Button title="Log In" onPress={this.toggleLoggedInState} />;
}
const items = list.reduce((array, item) => {
array.push(
<ListItem
key={j}
title={item.name}
onPress={item.onPress)
/>
);
return array;
}, []);
return (
<SideMenu>
<List>
{items}
</List>
{button}
</SideMenu>
)
}
}
export default Example;
If you want to change the state elsewhere and have this view respond, you'd be better off using something like redux under the hood. That gives you an underlying state for your whole app.