React Native: filtering props? - javascript

I created a basic component such as:
export default (props) => (
<TouchableOpacity {...props} style={styles.button}>
{props.title && <Text style={styles.text}>{props.title}</Text>}
{props.icon && <Icon name={props.icon} />}
</TouchableOpacity>
);
I can then call it with <Component title="Home" icon="home" /> for instance.
The problem is that passing {...props} to TouchableOpacity generate errors because it does not recognize title nor icon properly.
For instance:
JSON value 'Home' of type NSString cannot be converted to...
Is there a way to filter props so that I only pass valid ones for TouchableOpacity?

Transferring Props
Sometimes it's fragile and tedious to pass every property along. In that case you can use destructuring assignment with rest properties to extract a set of unknown properties.
List out all the properties that you would like to consume, followed by ...other.
var { checked, ...other } = props;
This ensures that you pass down all the props EXCEPT the ones you're
consuming yourself.
function FancyCheckbox(props) {
var { checked, ...other } = props;
var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
// `other` contains { onClick: console.log } but not the checked property
return (
<div {...other} className={fancyClass} />
);
}
ReactDOM.render(
<FancyCheckbox checked={true} onClick={console.log.bind(console)}>
Hello world!
</FancyCheckbox>,
document.getElementById('example')
);

Like Paul Mcloughlin, I would recommend using object destructuring along with a rest parameter. You can destructure your props object directly in your function parameters like so:
({title, icon, ...remainingProps}) => (...)
This extracts the title and icon props from your props object and passes the rest as remainingProps.
Your complete component would be:
export default ({title, icon, ...remainingProps}) => (
<TouchableOpacity {...remainingProps} style={styles.button}>
{title && <Text style={styles.text}>{title}</Text>}
{icon && <Icon name={icon} />}
</TouchableOpacity>
);

Related

React component. Render specific element

Currently I've a component User, which renders 2 element -> username and avatar.
I'm getting the username and avatar perfectly, but I want to view only the username only
Is there any way to fetch only the username element ? Not with a profile picture.
//User component
const User = ({ username, profilePic }) => {
return (
<React.Fragment>
<Avatar name='user' src={profilePic.profile.image} alt="user_image" ml="5"/>
<Heading size={'sm'} ml="5">{username.username}</Heading>
</React.Fragment>
);
};
// Content Page
{group.members.map(member => {
return <React.Fragment key={member.id}>
<User username={member.user} profilePic={member.user}/>
</React.Fragment>
})}
You could add an extra prop renderAvatar and only display the avatar if the boolean is true with conditional rendering.
const User = ({ username, profilePic, renderAvatar }) => {
return (
<React.Fragment>
{renderAvatar && <Avatar name='user' src={profilePic.profile.image} alt="user_image" ml="5"/>}
<Heading size={'sm'} ml="5">{username.username}</Heading>
</React.Fragment>
);
};
You could use it like this.
<User username={member.user} profilePic={member.user} renderAvatar={false} />
<User username={member.user} profilePic={member.user} renderAvatar={true} />
Or just create a component that only renders the Heading.
const UserWithoutAvatar = ({ username }) => {
return <Heading size={'sm'} ml="5">{username.username}</Heading>
};
One option would be to conditionally render based on whether or not profilePic is provided at all. For example:
return (
<React.Fragment>
{ profilePic ?
<Avatar name='user' src={profilePic.profile.image} alt="user_image" ml="5"/>
: null
}
<Heading size={'sm'} ml="5">{username.username}</Heading>
</React.Fragment>
);
Then if you just don't provide profilePic it will be undefined:
<User username={member.user} />
As an aside, the code seems to be generating confusion around naming. For example:
{username.username}
A property called "username" implies that it is a string representing the user's name. But in this case username is an object containing a property called username? Does that property contain a string? Or another object?
Or here:
<User username={member.user} profilePic={member.user}/>
What is member.user? Is it a username? Is it a profile pic? Somehow it's both?
Clarity is important. If what you're actually passing to the component is a user object then call it that:
<User user={member.user} />
Alternatively, if the component is expecting a literal value for username and a literal value for profilePic then pass it those values:
<User username={member.user.username} profilePic={member.user.profile.image} />
Don't confuse your semantics. Confusion leads to bugs.

Passing reference in react native functional components

I am new to react-native and I am using reanimated-bottom sheet in my project and I want to control this from other functional component called as Comment.
in my main component I am passing the reference of the sheet as
<Comment ref={ref} />
but when I receive it in my comment component it says cant find variable ref
const Comment =({ref}) => {
....
<TouchableOpacity
style={styles.panelButton}
onPress={() => ref.current.snapTo(1)}>
<Text>Cancel</Text>
</TouchableOpacity>
</View>
...
}
all I want is to close the sheet from my comment component without changing it to class component.
ref is predefined property so it won't be passed to the component.
You'd better use callback instead of passing ref.
<Component ref={ref} onPressButton={() => { ref.current.snapTo(1) }} />
const Comment =({ onPressButton }) => {
....
<TouchableOpacity
style={styles.panelButton}
onPress={onPressButton}>
<Text>Cancel</Text>
</TouchableOpacity>
....
}

Error: Cannot read property 'navigate' of undefined

enter image description hereWhen using navigation v5, I encounter an error can not read property navigate of undefined
const Categories=({navigation})=> {
return (
<View >
<Text style={Styles.TextCategories}>دسته بندی ها</Text>
{/* ---------------------------------------------------------------لایه کلی صفحه---------------------------------- */}
<View style={Styles.View}>
{/* --------------------------------------------------------------- لایه دکمه ها---------------------------------- */}
<Button style={Styles.Button} onPress={()=>navigation.navigate('Homesales')}>
<MaterialIcons name="waves" size={30} color={"#0c7656"} />
<Text style={Styles.Text}>زمین</Text>
</Button>
const Home=()=>{
useEffect(()=>{
axios.get('https://jsonplaceholder.typicode.com/posts').then((response)=>console.log(response.data)).catch((e)=>console.log(e))
},[])
return (
<Categories/>
);
}
export default React.memo(Home);
why don't you use navigation hook of react-navigation-v5?? instead of passing navigation as prop try to "useNavigation()" hook, this way you will have access to a valid navigation object from anywhere
const navigation=useNavigation()
for using navigation
navigation.navigate('')
You are passing a object that does not has property 'navigation' to component Categories
You need to check at the parent component, seem that props/navigation is null here.

Render button in child component only on certain screen

Im using a flat list on 2 different screens.
On the EventListScreen:
this is the main screen and should display all events.
and on the 2nd page UserProfile.js this page should only display that users events.
in both flat lists I'm using a pure component stored in a seperate class, to where the flat lists are i.e
My Question is, I want to display an "Edit" button on the Event.js child component only if the User is on the
UserProfileScreen.js
I have looked up a lot of example but cant really find any that show how to do it
with a child pure component like I'm doing.
Any Help would be greatly appreciated! Thank you
EventListScreen.js
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
{...item}
/>}
/>
UserProfileScreen.js
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
openEditEvent={() => this.openEditEvent(item)}
{...item}
/>}
/>
Event.js
export default class Event extends Component {
render() {
return (
<Card>
<CardSection>
<Text>{this.props.eventName}</Text>
//I want this button to be displayed only if user is viewing
//from the UserProfile.js
<Button onPress={() =>this.props.openEditEvent()}>
{this.props.displayButton}
</Button>
</CardSection>
<TouchableOpacity
onPress={() => this.props.openEventDetail()}
>
}
You don't need additional properties.
We can assume that the "Edit" button should be available when openEditEvent prop is defined.
Condition in event (using convertion to bool, false for undefined):
<CardSection>
<Text>{this.props.eventName}</Text>
{!!this.props.openEditEvent &&
<Button onPress={() =>this.props.openEditEvent()}>
{this.props.displayButton}
</Button>
}
</CardSection>
Use propTypes to define openEditEvent prop as a function, optional (not required).
If I understand your problem correctly an option to solve this problem would be to pass a boolean "showable prop" to show the edit button only when required:
EventListScreen.js (Stays the same, we don't show the edit button here)
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
{...item}
/>}
/>
UserProfileScreen.js (we add the shouldShowEditButton prop to event in order to show the button)
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
openEditEvent={() => this.openEditEvent(item)}
shouldShowEditButton
{...item}
/>}
/>
Event.js (We add some propTypes and defaultProps to handle the new prop, it won't show the edit button if not specified)
export default class Event extends Component {
render() {
return (
<Card>
<CardSection>
<Text>{this.props.eventName}</Text>
//I want this button to be displayed only if user is viewing
//from the UserProfile.js
{this.props.shouldShowEditButton && <Button onPress={() =>this.props.openEditEvent()}>
{this.props.displayButton}
</Button>}
</CardSection>
<TouchableOpacity
onPress={() => this.props.openEventDetail()}
>
...
...
);
...
}
}
// We add some default propTypes and definitions
Event.propTypes = {
shouldShowEditButton: PropTypes.bool
};
Event.defaultProps = {
shouldShowEditButton: false
};
In this way you're only showing the edit button for the components that have the prop shouldShowEditButton defined, and because its default value is defined as false, the components that don't have the property will behave in the same way they were before.

Admin-On-Rest Customizing Inputs

I have a User Resource, which referenced by many other resources.
So I want to create a UserResourceInput :
import React from 'react';
import {ReferenceInput, SelectInput} from 'admin-on-rest';
const UserReferenceInput = (props) => (
<ReferenceInput reference="user" {...props}>
<SelectInput optionText="name"/>
</ReferenceInput>
);
UserReferenceInput.defaultProps = {
source: 'userId',
addLabel: true,
label: 'User'
};
export default UserReferenceInput;
And Use it in simple form like this:
ProductCreate = (props) => (
<Create {...props}>
<SimpleForm>
<TextInput source="title" />
<NumberInput source="price" />
<UserReferenceInput />
</SimpleForm>
</Create>
);
But I get this Error:
You are missing the source prop on the ReferenceInput. Hence, it can't find value for it. You can define it either inside the UserReferenceInput directly or pass it as prop to the UserReferenceInput in your form.
Edit
Don't use the addLabel prop on the ReferenceInput, it does not support it. Instead, apply it on the SelectInput child.

Categories