Conditionally rendering a child component into Header in React Native - reactjs

In my react-native 0.62 app, I created an <AppHeader /> component to render the header so that I don't have to repeat the same code in every screen.
The title and burger menu are standard and always there but in some screens, I want to add one, two or more buttons to the right section -- see below:
So, it would be nice to receive and render a component on the right. If no component is received, then I wouldn't render anything and the right side would be blank.
I'm using native-base so the header understands <Left> and <Right>.
My question is how would I pass a component to my <AppHeader /> and what would the conditional part look like?
Here's my <AppHeader /> component now:
import React from 'react';
import { Header, Left, Body, Right, Button, Icon, Title } from 'native-base';
// Stylesheet
import { styles } from './style-app-header';
const AppHeader = ({ navigation, title, rightSection }) => {
return (
<Header transparent>
<Left style={{ flex: 1 }}>
<Button transparent onPress={() => navigation.navigation.openDrawer()}>
<Icon name="ios-menu" style={styles.icon} />
</Button>
</Left>
<Body style={{ flex: 1 }}>
<Title style={styles.title}>{title}</Title>
</Body>
{
rightSection === null
? <Right />
: <Right style={{ flex: 1 }}>
// How would I render the component here?
</Right>
}
</Header>
);
}
export default AppHeader;

React components can be used just like any other variable value.
const buttons = <button onClick={someAction}>Click me!</button>;
return (
<AppHeader rightSection={buttons}/>
);
// ...
<Right style={{ flex: 1 }}>
{rightSection}
</Right>
// ...

Related

How to prevent HTML5 audio element from redirecting to the home route when clicked?

I'm working on implementing theme music into my React game. There are three routes currently, which are rendered by my 'App' component (which is wrapped by BrowserRouter) like so:
<div>
<div style={{display: 'flex', justifyContent: 'flex-end', position: 'relative', top: '2vh', right: '1vw'}}>
<Audio />
</div>
<Switch>
<Route exact path='/'>
<Menu />
</Route>
<Route path='/gameover'>
<GameOver points={totalScore} numWords={totalWords} longestWord={longestWord} tilesCleared={tilesCleared} />
</Route>
<Route path='/game/:difficulty'>
<BoardHolder />
</Route>
</Switch>
</div>
I want my 'Audio' component to be accessible from each route, which is why I have rendered it outside of my 'Switch' tags. The audio does work, and it can be accessed from every route. However, if my Audio component is clicked on from any route besides '/', it redirects the user to '/'. This is not ideal, as I would like to be able to toggle the music on/off while in the middle of a game (or at the GameOver route).
This is how my audio component is set up:
import audio from "../../Station-X.webm";
const Audio = () => {
const theme = useSelector(state => state.theme);
return (
<div
style={{
// Omitted
}}>
<button
style={{
// Omitted
}}
onClick={e => {
// Next two buttons play/pause music. Functionally speaking, they work fine.
// However, I do not want to be redirected to '/' upon a click.
// e.preventDefault() does not prevent redirect, nor does 'return false'
e.preventDefault();
document.getElementById('music-player').play()
return false;
}}>
<i className="fa-sharp fa-solid fa-volume-high"></i>
</button>
<button
style={{
// Omitted
}}
onClick={e => {
e.preventDefault();
document.getElementById('music-player').pause()
return false;
}}>
<i className="fa-sharp fa-solid fa-volume-xmark"></i>
</button>
<audio id='music-player' autoPlay loop>
<source src={audio} type="audio/mpeg" />
</audio>
</div>
);
};
I can't find a solution to this anywhere. Any insight would be appreciated.

Image is missing required "src" property. Make sure you pass "src" in props to the `next/image` component. İ got really stuck this time

Image is missing required "src" property. Make sure you pass "src" in props to the next/image component. İ got really stuck this time. i've checked everywhere but didnt fixed it
import Link from "next/link";
import Image from "next/image";
import { Flex, Box, Text, Button } from "#chakra-ui/react";
const Banner = ({
purpose,
imageUrl,
buttonText,
linkName,
title1,
title2,
desc1,
desc2,
}) =>
(
<Flex flexWrap="wrap" justifyContent="center" alignItems="center" m="10">
<Image src={imageUrl} width="500" height="300" alt="banner"/>
<Box p="5">
<Text color="gray.500" fontSize="sm" fontWeight="medium">
{purpose}
</Text>
<Text fontSize="3xl" fontWeight="bold">
{title1} <br /> {title2}
</Text>
<Text
fontSize="lg"
paddingTop="3"
paddingBottom="3"
color="gray.700"
fontWeight="medium"
>
{desc1}
<br />
{desc2}
</Text>
<Button fontSize="xl" bg="blue.300" color="white">
<Link href={linkName}>{buttonText}</Link>
</Button>
</Box>
</Flex>
);
export default function Home() {
return (
<div>
<h1>Emlak Evim</h1>
<Banner
purpose="Ev Kirala"
title1="Kiralık Evler"
title2="Herkes için"
desc1="Daireleri keşfedin"
desc2="ve daha fazlası"
buttonText="Kiralık Evleri keşfet"
linkName="/search?purpose=for-rent"
imageUrl="https://bayut-production.s3.eu-central-1.amazonaws.com/image/145426814/33973352624c48628e41f2ec460faba4"
/>
<Banner purpose={"kiralıkk"} />
<Banner
purpose="Ev Satın Al"
title1="Bul ve Satın Al"
title2="Hayalinizdeki Evinizi Bulun"
desc1="Daireleri, Villaları, Yazlıkları keşfedin"
desc2="ve daha fazlası"
buttonText="Satılık Evleri keşfet"
linkName="/search?purpose=for-sale"
imageUrl="https://bayut-production.s3.eu-central-1.amazonaws.com/image/110993385/6a070e8e1bae4f7d8c1429bc303d2008"
/>
<Banner purpose={"kiralıkk"} />
</div>
);
}
// next config file.
module.exports = {
reactStrictMode: true,
images:{
domains:['bayut-production.s3.eu-central-1.amazonaws.com']
},
}
You try to render <Banner purpose={"kiralıkk"} /> without imageUrl prop given, so <Image/> gets this prop undefined

Passing props to children in a composition model

I'm using composition model a, I have one parent element that have many children.
I'm wondering if it is possible to get the props of the parent element inside the children.
For now i'm passing the same props to all the component (parent and child) but I guess there is better way to do that.
Here the parent element
const ImageTop = ({ results, children }) => {
const navigation = useNavigation();
return (
<>
<ImageBackground
style={{ height: height * 0.25, width: "100%" }}
source={imageToDisplay(results)}
>
<Pressable style={styles.blocArrow} onPress={() => navigation.goBack()}>
<Ionicons name="arrow-back-outline" size={32} color="white" />
</Pressable>
<TransparentsBar results={results} />
</ImageBackground>
<View style={{ marginLeft: 15, paddingTop: 15 }}>{children}</View>
</>
);
};
And here I'm passing components as children of the parent component :
const DetailsEvents = ({ route }) => {
const [results] = useState(route.params.item);
return (
<ScrollView showsVerticalScrollIndicator={false}>
<ImageTop results={results}>
<GenreAndTitle results={results} />
<Address results={results} />
<Date results={results} />
<CTA results={results} />
<Description results={results} />
<OrganizedBy results={results} />
</ImageTop>
</ScrollView>
);
};
So as you can see I'm sending the same props "Results" to all components which is ugly ... I'd like to send the props only to the parent and the children get access to that props. Is there any way to do that ?
Thank you
You can use React Context. This will remove the redundancy regarding sending same props to all those child components separately. What you will be doing is create a context having the value you want your application to use globally and wrap your root elements with that context's Provider. Then the value will be available to all your child components which you can access and modify with useContext.

How to change tabs width in material UI

I am using material UI tabs v0.20.0 for display content in tabular format. Tabs are taking full width. I have attached screenshot of expected and current output .
Expected output
Current Output
Please let me know a solution for the same.
If you want tabs of fixed width, you need to override the root css class passed to the Tab component, where you have to override both the minWidth and width attributes.
Example:
const Component = ({ classes }) => (
<Tabs value={0}>
<Tab classes={{ root: classes.tab }} label="One" />
<Tab classes={{ root: classes.tab }} label="Two" />
</Tabs>
);
// this is injected as classes prop into the wrapping component
const styles = {
tab: {
minWidth: 200, // a number of your choice
width: 200, // a number of your choice
}
};
export default withStyles(styles)(Component);
The Tabs component does accept a variant prop. One of the following string values are accepted:
fullWidth -> which is OPs current result
standard -> which is the default
scrollable -> adding scrolling functionality via buttons if not all tab items are visible
By now, the OPs expected result should be the default prop (standard).
Official Docs:
Tabs Guide: https://material-ui.com/components/tabs/
Tabs API: https://material-ui.com/api/tabs/
setting the minWidth to 50% does the job
<Tabs value={value} style={{backgroundColor:"#121858",color:"#FFF"}} onChange=
{handleChange} aria-label="simple tabs example" >
<Tab label="Tab One" {...a11yProps(0)} style={{minWidth:"50%"}}/>
<Tab label="Tab Two" {...a11yProps(1)} style={{minWidth:"50%"}}/>
</Tabs>
responsive solution :-
<Tabs variant="fullWidth"> </Tabs>
You're going to have to hardcode a tab width:
const width = 200;
const widthModifier = {
width: `${width}px`,
};
And then apply it to change the tab width:
<Tab label="Item One" style={widthModifier}>
You're also going to have to keep track of the current active tab using onActive and calculate the displacement of the ink bar yourself. Here's a full working example:
import React, { Component } from 'react';
import {Tabs, Tab} from 'material-ui/Tabs';
const styles = {
headline: {
fontSize: 24,
paddingTop: 16,
marginBottom: 12,
fontWeight: 400,
},
};
const width = 200;
const widthModifier = {
width: `${width}px`,
};
class TabWidth extends Component {
constructor(props) {
super(props);
this.state = { selectedIndex: 0 };
}
render() {
const { selectedIndex } = this.state;
// Notice that I have to calculate the left position of the ink bar here for things to look right
return (
<Tabs inkBarStyle={ {left: `${width * selectedIndex}px`, ...widthModifier}}>
<Tab label="Item One" style={widthModifier} onActive={() => this.setState({ selectedIndex: 0 })}>
<div>
<h2 style={styles.headline}>Tab One</h2>
<p>
You can put any sort of HTML or react component in here. It even keeps the component state!
</p>
</div>
</Tab>
<Tab label="Item Two" style={widthModifier} onActive={() => this.setState({ selectedIndex: 1 })}>
<div>
<h2 style={styles.headline}>Tab Two</h2>
<p>
This is another example tab.
</p>
</div>
</Tab>
</Tabs>
);
}
}
export default TabWidth;
But, you really should be using v1 if possible. In material-ui v1, your desired tab behavior is the default right out of the box and will scale based on screen size.
I had this question. You need to just simply add fullWidth to Tabs component link:
<Tabs variant="fullWidth" value={value} onChange={this.handleChange} aria-label="simple tabs example">
<Tab className={classes.root} label={t('login')} />
<Tab className={classes.root} label={t('register')} />
</Tabs>
it worked for me.

React native toggle component without state

I just want to toggle SearchButton and SearchIcon , I use following code
searchBarButton() {
Actions.refresh();
this.setState({ showSearchBar: !this.state.showSearchBar });
}
render() {
if (this.state.showSearchBar) {
return (
<Header>
<View style={styles.searchHolder}>
<Item style={styles.searchBar}>
<Icon name="ios-search" />
<Input placeholder="Search" />
</Item>
<Button style={styles.searchButton} onPress={this.searchBarButton}>
<Text>Search</Text>
</Button>
</View>
</Header>
);
}
return (
<Header>
<Button onPress={() => this.searchBarButton()} transparent>
<Icon name="search" style={styles.bigblue} />
</Button>
</Header>
);
}
So basically It is very fast initially , But when my scene contains lots of items in flat List , There is like 1 to 2 seconds delay between toggle.I guess its due to re-rendering all items in page.
So How can I toggle this in more easier and efficient way without Re rendering whole page without using state
I think you have to hide one of them by using style prop.
Just render both first, toggle one of them to be hidden(by using state),
<Header>
<View style={[this.state.showSearchBar && styles.hidden]}>Button</View>
<View style=[{!this.state.showSearchBar && styles.hidden}]>Icon</View>
</Header>
do not remove them from virtual dom(I don't know what to call it in mobile) completely
I'd recommend you to grab some UI library. Take a look at this: https://react-bootstrap.github.io/components.html#utilities
You can just trow you your searchbar code in this
<Collapse in={this.state.showSearchBar}>
...
</Collapse>
And everything is taken care of very efficiently.
You just need to trow your button in an operator {!showSearhBar && <Component/>}
Also use react dev tools to check what re-renders

Resources