get padding, margin and width of react-native elements - javascript

I am trying to make a component appear between other components. For that, I would like to create a generic wrapper able to calculate the size of its child component and create the correct animation.
So far, I succeeded (with a lot of trouble) to somehow make the component appear as expected when the size of the child element is hard coded. But It doesn't work as soon as a padding or margin is set...
See my test case here:
import React from "react";
import ReactDOM from "react-dom";
import { View, Text, TouchableOpacity } from "react-native-web";
import styled from "styled-components";
const Container = styled(View)`
flex-direction: row;
`;
//The button that will make the component appear
class Toggle extends React.PureComponent {
render() {
return (
<TouchableOpacity {...this.props}>
<Text>Press Me</Text>
</TouchableOpacity>
);
}
}
//This wrapper will carry the appearing animation
const Wrapper = styled(View)`
transition: all ${props => props.delay}s ease;
transform: scale(${props => (props.mount ? 1 : 0)});
width: ${props => (props.mount ? props.width : 0)}px;
`;
//This is the component in charge of the appearing effect
class Appearing extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
mounted: false,
render: false,
width: 0
};
}
//This will start the animation
componentDidMount() {
this.setState({ mounted: true, render: true });
}
componentDidUpdate() {
//this will start the disappearing animation
if (this.state.mounted && !this.props.mount) {
this.setState({ mounted: false });
setTimeout(
() => this.setState({ render: false }),
this.props.delay * 1000
);
//this will restart the appearing animation
} else if (!this.state.mounted && this.props.mount) {
this.setState({ mounted: true, render: true });
}
//We read the expected this of the child component
this.setState({ width: this.getWidth ? this.getWidth() : 0 });
}
render() {
return (
<Wrapper {...this.props} width={this.state.width}>
{React.cloneElement(this.props.children, {
//We read the child size with the 'onLayout' method
onLayout: event =>
(this.getWidth = () => event.nativeEvent.layout.width)
})}
</Wrapper>
);
}
}
//Carry the test case
class App extends React.PureComponent {
state = { toggle: false };
render() {
return (
<View>
{/* with only the width set */}
<Container>
<Appearing delay={0.5} mount={this.state.toggle}>
<Text style={{ width: "9em" }}>Tadaaaaaaaa !</Text>
</Appearing>
<Toggle
onPress={() => this.setState({ toggle: !this.state.toggle })}
/>
</Container>
{/* with the width and padding set */}
<Container>
<Appearing delay={0.5} mount={this.state.toggle}>
<Text style={{ width: "9em", paddingLeft: "10em" }}>
Tadaaaaaaaa !
</Text>
</Appearing>
<Toggle
onPress={() => this.setState({ toggle: !this.state.toggle })}
/>
</Container>
</View>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Do you know the best way to achieve that?

Related

How to change css code by pressing a button

Goal:
When you press on the button 'ok', the id element named test2 should be display non and id element named test1 should be display block with support of css code.
And also please take account to the color of the text that is located in the css code.
Problem:
I don't know how to solve it.
What is needed to be changed in the source code in order to achieve the goal?
Stackblitz:
https://stackblitz.com/edit/react-modal-gdh4hp?
Info:
*I'm newbie in Reactjs
Thank you!
index.js
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Modal } from './modal';
import './style.css';
class App extends Component {
constructor() {
super();
this.state = {
modal: true
};
}
handleCloseModal = () => {
alert('ddd');
};
render() {
const { modal } = this.state;
const non = {
display: 'none',
color: 'yellow'
};
const block = {
display: 'block',
color: 'yellow'
};
return (
<div>
{modal ? (
<Modal
onClose={() => {
this.setState({ modal: false });
}}
>
<div id="test1" style={non}>Awesome1</div>
<div id="test2">Awesome2</div>
<button onClick={() => this.handleCloseModal()}>ok</button>
</Modal>
) : (
<button
onClick={() => {
this.setState({ modal: true });
}}
>
Show modal
</button>
)}
</div>
);
}
}
render(<App />, document.getElementById('root'));
modal.js
import React from 'react';
export class Modal extends React.Component {
render() {
const { children, onClose } = this.props;
return (
<div style={{position: "absolute", top: 0, left: 0, width: "100%", height: "100%", background: "gray"}} onClick={ev => onClose()}>
<div
style={{margin: "auto", background: "white", border: "red", width: "500px", height: "300px"}}
onClick={ev => ev.stopPropagation()}>
{ children }
</div>
</div>
);
}
}
You can simply do that :
ok() => {
document.getElementById('test1').style.display = 'block'
document.getElementById('test2').style.display = 'none'
}
You can use state
class App extends Component {
constructor() {
super();
this.state = {
modal: true,
showBlock: "",
showNon: "",
color: ""
};
}
handleCloseModal = () => {
this.setState({showBlock: "block"});
this.setState({showNon: "none"});
this.setState({color: "yellow"});
alert('ddd');
};
render() {
const { modal } = this.state;
return (
<div>
{modal ? (
<Modal
onClose={() => {
this.setState({ modal: false });
}}
>
<div id="test1" style={{display: this.state.showBlock, color: this.state.color}}>Awesome1</div>
<div id="test2" style={{display: this.state.showNon, color: this.state.color}}>Awesome2</div>
<button onClick={() => this.handleCloseModal()}>ok</button>
</Modal>
) : (
<button
onClick={() => {
this.setState({ modal: true });
}}
>
Show modal
</button>
)}
</div>
);
}
}
render(<App />, document.getElementById('root'));
React way to achieve that is to use useRef hook (or createRef for class approach):
Class approach:
constructor(props) {
this.testRef = React.createRef()
}
const toggleBlock = () => {
testRef.current.style.display = 'block'
testRef.current.style.color = 'yellow'
}
render() {
return (
<>
<div id="test1" ref={testRef}>Awesome1</div>
<button onclick={this.toggleBlock}>Ok</button>
</>
)
}
Hooks approach:
const testRef = useRef(null)
const toggleBlock = () => {
testRef.current.style.display = 'block'
testRef.current.style.color = 'yellow'
}
return (
<>
<div id="test1" ref={testRef}>Awesome1</div>
<button onclick={this.toggleBlock}>Ok</button>
</>
)

Press tab to scroll to top of flatlist

I would like to implement scrolling to top. My tab is a flatlist, and when users scroll down the flatlist, they have to scroll back up. Instagram and Twitter allow you to press the tab to scroll back up, I am wondering how to implement it in my own app.
Here is the tab I want to implement scrolling to top:
//Bottom Tabs
function Tabs() {
...
<Tab.Screen
name="Home"
component={globalFeedStackView}
options={{
tabBarLabel: ' ',
tabBarIcon: ({ color, size }) => (
<Ionicons name="ios-home" size={size} color={color} />
),
}}
/>
}
And the class component for the tab above:
class GlobalScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
globalPostsArray: [],
navigation: this.props.navigation,
};
}
async componentDidMount() {
this.getCollection()
Analytics.setUserId(Firebase.auth().currentUser.uid)
Analytics.setCurrentScreen("GlobalScreen")
}
...
render() {
return (
<View style={styles.view}>
<FlatList
data={this.state.globalPostsArray}
renderItem={renderItem}
keyExtractor={item => item.key}
contentContainerStyle={{ paddingBottom: 50 }}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
onRefresh={this._refresh}
refreshing={this.state.isLoading}
onEndReached={() => {this.getMore()}}
/>
<KeyboardSpacer />
</View>
)
}
According to react navigation I can do something like this:
import * as React from 'react';
import { ScrollView } from 'react-native';
import { useScrollToTop } from '#react-navigation/native';
class Albums extends React.Component {
render() {
return <ScrollView ref={this.props.scrollRef}>{/* content */}</ScrollView>;
}
}
// Wrap and export
export default function(props) {
const ref = React.useRef(null);
useScrollToTop(ref);
return <Albums {...props} scrollRef={ref} />;
}
But this solution is for a scrollview, and I am using a flatlist.
How can I implement pressing a tab to scroll to the top of my flatlist?
scrollToOffset
you can do it the same way with a ref on your FlatList :
import * as React from 'react';
import { FlatList } from 'react-native';
class Albums extends React.Component {
render() {
return <FlatList ref={this.props.scrollRef} />;
}
// Wrap and export
export default function(props) {
const ref = React.useRef(null);
ref.scrollToOffset({ animated: true, offset: 0 });
return <Albums {...props} scrollRef={ref} />;
}

React-images carousel

I am trying to achieve an image/video carousel using https://jossmac.github.io/react-images/
and it should be like this including modal :
I following the code snippet given there but it's not working and I don't see any step by step guide to making that carousel.
class Gall extends Component {
state = { modalIsOpen: false }
toggleModal = () => {
this.setState(state => ({ modalIsOpen: !state.modalIsOpen }));
}
render() {
const { modalIsOpen } = this.state;
return (
<ModalGateway>
{modalIsOpen ? (
<Modal onClose={this.toggleModal}>
<Carousel views={images} />
</Modal>
) : null}
</ModalGateway>
);
}
}
export default Gall;
can anyone please help with a codesandbox?
Also is it possible to trigger the modal with the current active image?
Thanks in advance.
There is a link in their docs to the source
// #flow
// #jsx glam
import glam from 'glam';
import React, { Component, Fragment } from 'react';
import { type ProviderProps } from '../../ImageProvider';
import Carousel, { Modal, ModalGateway } from '../../../src/components';
import { FooterCaption } from '../components';
import { getAltText } from '../formatters';
type State = {
selectedIndex?: number,
lightboxIsOpen: boolean,
};
export default class Home extends Component<ProviderProps, State> {
state = {
selectedIndex: 0,
lightboxIsOpen: false,
};
toggleLightbox = (selectedIndex: number) => {
this.setState(state => ({
lightboxIsOpen: !state.lightboxIsOpen,
selectedIndex,
}));
};
render() {
const { images, isLoading } = this.props;
const { selectedIndex, lightboxIsOpen } = this.state;
return (
<Fragment>
{!isLoading ? (
<Gallery>
{images.map(({ author, caption, source }, j) => (
<Image onClick={() => this.toggleLightbox(j)} key={source.thumbnail}>
<img
alt={caption}
src={source.thumbnail}
css={{
cursor: 'pointer',
position: 'absolute',
maxWidth: '100%',
}}
/>
</Image>
))}
</Gallery>
) : null}
<ModalGateway>
{lightboxIsOpen && !isLoading ? (
<Modal onClose={this.toggleLightbox}>
<Carousel
components={{ FooterCaption }}
currentIndex={selectedIndex}
formatters={{ getAltText }}
frameProps={{ autoSize: 'height' }}
views={images}
/>
</Modal>
) : null}
</ModalGateway>
</Fragment>
);
}
}
const gutter = 2;
const Gallery = (props: any) => (
<div
css={{
overflow: 'hidden',
marginLeft: -gutter,
marginRight: -gutter,
}}
{...props}
/>
);
const Image = (props: any) => (
<div
css={{
backgroundColor: '#eee',
boxSizing: 'border-box',
float: 'left',
margin: gutter,
overflow: 'hidden',
paddingBottom: '16%',
position: 'relative',
width: `calc(25% - ${gutter * 2}px)`,
':hover': {
opacity: 0.9,
},
}}
{...props}
/>
);

How to expand search bar after presses on search icon

I am somehow create an Search icon by a component and I just wanna know how to expand search bar icon when someone presses on it..
import { TouchableOpacity,View, Image} from 'react-native';
import { SearchBar } from 'react-native-elements';
export default class Search extends Component{
onClick(){
return <SearchBar/> // [![Seach Image][1]][1]not working
}
render(){
// not worrking
let search = <SearchBar/>;
return(
<View>
<TouchableOpacity
onPress={() => {
return search
}}
>
<Image
source={require('../images/tabs/search.png')}
style={{height: 40, width: 60}}
resizeMode={'contain'}
/>
</TouchableOpacity>
</View>
)
}
}
You should add a state to your component to control the behaviour of the header
import { TouchableOpacity, View, Image } from 'react-native';
import { SearchBar } from 'react-native-elements';
export default class Search extends Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
this.state = {
showSearchBar: false, // control what ever to render the searchbar or just the icon
};
}
onClick() {
let { showSearchBar } = this.state;
this.setState({
showSearchBar: !showSearchBar,
});
}
render() {
const { showSearchBar } = this.state;
return (
<View>
{!showSearchBar ? (
<TouchableOpacity onPress={this.onClick}>
<Image
source={require('../images/tabs/search.png')}
style={{ height: 40, width: 60 }}
resizeMode={'contain'}
/>
</TouchableOpacity>
) : (
<SearchBar />
)}
</View>
);
}
}

How to share or to recive some data from second screen In React Native

I have 2 screens, my Home Screen
class Home extends Component {
constructor(props) {
super(props)
this.state = {
myDebts: 745.8455656,
debts: 1745.54555
}
}
addFriendsHandler = () => {
Alert.alert('You tapped the button!')
}
render () {
return (
<View style={{flex: 1}}>
<Header
text={"Splitwise"} />
<Debts
myDebts={this.state.myDebts}
debts={this.state.debts}/>
<Buttons text={"+ ADD FRIENDS ON SPLITWISE"}
clicked={() => this.props.navigation.navigate("AddFriend")}/>
</View>
)
}
}
export default Home
and my second Screen
class AddFriendPage extends Component{
state = {
name: ''
}
addFriendHandler = () => {
this.props.navigation.navigate("MainPage")
}
render() {
return (
<View>
<Header text={"Add a friend"}/>
<Sae
label={'Your friends name'}
labelStyle={{ color: '#47AE4f' }}
iconClass={FontAwesomeIcon}
iconName={'pencil'}
iconColor={"#47AE4f"}
inputStyle={{ color: '#000' }}
onBlur={(e) => this.setState({name: e.nativeEvent.text})}
/>
<Buttons text={"+ ADD FRIEND"}
disable={this.state.name === ''}
clicked={this.addFriendHandler}/>
</View>
)
}
}
and my Navigator
export default class App extends React.Component {
render() {
return (
<AppStackNavigator />
);
}
}
const AppStackNavigator = createStackNavigator({
MainPage: Home,
AddFriend: AddFriendScreen
})
I want to send a function to the AddFriendPage screen from Home screen, and inside that function i want to get value from input and return the name back into Home screen, but unfortunately i have no idea how to share data between 2 screens
https://reactnavigation.org/docs/en/params.html#docsNav
You want to pass params during navigation:
() => this.props.navigation.navigate("AddFriend", {name: "Alan"})
Then in the parent method (if you want to display it, you could just put it in render):
const name = this.props.navigation.getParam(name, null)
If null, you know that the screen was reached from a different screen, and can handle that case normally. You can add whatever params you want.

Categories