Pass state from component to Modal? - javascript

I have a component and import it in specific screen, in this screen i have a button when clicks i open modal contain component it's a "recorder" so after i record voices i want to take this voice and save them into Parent screen as a state or something!
in the recorder component, I save voices data into state! but how can i pass it to other parent screens!?
so how can I handle it?
here is shots
Parent Screen "after click add voice I show the modal"
Parent Screen
Here's a modal contain a recorder component
Modal
CODE
Component
" I pass data to PassDataToModal state inside componentDidMount "
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, TouchableOpacity, View} from 'react-native';
import {AudioRecorder, AudioUtils} from 'react-native-audio';
import Sound from 'react-native-sound';
import Icon from 'react-native-vector-icons/MaterialIcons';
class RecorderScreen extends Component {
state = {
PassDataToModal: null,
};
componentDidMount() {
AudioRecorder.requestAuthorization().then(isAuthorised => {
this.setState({hasPermission: isAuthorised});
AudioRecorder.onFinished = data => {
console.log('data', JSON.stringify(data));
this.setState({PassDataToModal: data});
};
});
}
render() {
return (
<View style={styles.container}>
<View style={styles.controls}>
{this._renderPlayButton(() => {
this._play();
})}
{this._renderRecordButton(this.state.recording)}
{this._renderStopButton('Stop', () => {
this._stop().then(() => this.setState({currentTime: 0}));
})}
</View>
<Text style={styles.progressText}>{this.state.currentTime}s</Text>
</View>
);
}
}
export default RecorderScreen;
Parent Screen
import Modal from 'react-native-modal';
import RecorderScreen from './Recorder';
class Order extends Component {
constructor(props) {
super(props);
this.state = {
isModalVisible: false,
};
}
toggleModal = () => {
this.setState({isModalVisible: !this.state.isModalVisible});
};
render() {
return (
<View style={styles.container}>
<TouchableOpacity
onPress={this.toggleModal}
>
<Icon name="mic" color="#333" size={20} />
<Text style={{paddingHorizontal: 5}}>Add Voice</Text>
</TouchableOpacity>
<Modal
style={{margin: 0}}
isVisible={this.state.isModalVisible}
>
<View>
<TouchableOpacity onPress={this.toggleModal}>
<Icon name="close" color="#000" size={25} />
</TouchableOpacity>
<RecorderScreen /> // Component
</View>
</View>
)
}
}

In your parent component pass a function to your RecorderScreen component that will send the necessary data up. Docs on lifting state up.
So in your parent you'd have something like:
setData = (data) => {
// Set this to whatever you need it to be named
this.setState({childData: data});
}
Then pass the function as a prop:
<RecorderScreen setData={this.setData} />
And finally, call it in the child however needed (If I'm following the code something like this):
componentDidMount() {
AudioRecorder.requestAuthorization().then(isAuthorised => {
this.setState({hasPermission: isAuthorised});
AudioRecorder.onFinished = data => {
this.props.setData(data);
};
});
}
Then your parent component will have access to the child's data that you have lifted up.

Related

Call component through function React Native

I'm developing a component to publish it in npm, but I'd like to call my component using a method instead of a tag.
Example:
myComponent.js
import React from 'react'
import { View, Text } from 'react-native'
export const showComponent = () => {
// this would be the function that I user to call my component down
}
const myComponent = (props) => {
return(
<View>
<Text>Oi</Text>
</View>
)
}
App.js
import React from 'react'
import { View, Text, TouchableOpacity } from 'react-native'
import { showComponent } from 'my-component'
const App = () => {
return(
<View>
<TouchableOpacity onPress={() => showComponent()}>
<Text>Home</Text>
</TouchableOpacity>
</View>
)
}
export defaul App
the idea is that when calling the showComponent function I show my component, and when I call, for example, the hide function, I close my component.
You can do it using a single class export:
import * as React from 'react';
export default class MyComponent extends React.Component {
state = {
isOpen: false,
};
open = () => {
this.setState({ isOpen: true });
};
close = () => {
this.setState({ isOpen: true });
};
render() {
const { isOpen } = this.state;
return !isOpen ? null : (
<View>
<Text>Oi</Text>
</View>
);
}
}
And you use it like so:
<MyComponent ref={(x) => this.myComponent = x)} />
And you open it like so:
this.myComponent.open();
I see in a comment above you want to call the component with a redux action, so you should call your redux action in that on click, but the component you want to show/hide needs to be linked to a redux state variable. Then in your jsx you'd have:
<View>
<TouchableOpacity onPress={() => showComponent()}>
<Text>Home</Text>
</TouchableOpacity>
{reduxBoolean && <MyComponent />}
</View>
import React from 'react'
import { View, Text} from 'react-native'
const example = (props) => {
return (
<View>
<Text>Hello</Text>
</View>
)
}
// props
import React from 'react'
import { View, Text} from 'react-native'
const examples = () => {
return(
<View>
<Text><example/></Text>
</View>
)
}
and print is : Hello

How can I use react navigation props in class component?

I have created a Share icon which on click share's pdf or image file on social accounts like facebook, whatsapp, gmail, etc. I want to pass URL link of shareable file inside class component but getting error. If I hardcode the URL then it works fine but how can I pass URL which I receive from react navigation ?
Working code:
import React, { Component } from 'react';
import { Share, View, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
const shareOptions = {
title: 'Download Brochure',
url: 'https://cpbook.propstory.com/upload/project/brochure/5bc58ae6ca1cc858191327.pdf'
}
export default class Screen extends Component {
onSharePress = () => Share.share(shareOptions);
render() {
return (
<View>
<Text style={styles.infoTitle}>Share: </Text>
<TouchableOpacity onPress={this.onSharePress}>
<Icon style={{paddingLeft: 10, paddingTop: 10}}name="md-share" size={30} color="black"/>
</TouchableOpacity>
</View>
}
}
Above code works fine but below code gives error saying shareOptions is undefined. How can I overcome this problem ? I want to pass file URL inside shareOptions. I am getting file url from react navigation props i.e brochure.
Code:
import React, { Component } from 'react';
import { Share, View, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
export default class Screen extends Component {
onSharePress = () => Share.share(shareOptions); <---Getting error here shareOptions undefined
render() {
const project = this.props.navigation.getParam('project', null);
let { brochure } = project;
const shareOptions = {
title: 'Download Brochure',
url: brochure
}
return (
<View>
<Text style={styles.infoTitle}>Share: </Text>
<TouchableOpacity onPress={this.onSharePress}>
<Icon style={{paddingLeft: 10, paddingTop: 10}}name="md-share" size={30} color="black"/>
</TouchableOpacity>
</View>
)
}
How can I overcome above problem and how can I pass props i.e file URL in above case URL is in brochure props.
Just pass shareOptions object to onSharePress function as param and get shareOptions in onSharePress event handler function
import React, { Component } from 'react';
import { Share, View, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
export default class Screen extends Component {
onSharePress = (shareOptions) => {
Share.share(shareOptions);
}
render() {
const { navigation } = this.props;
const project = navigation.getParam('project', null);
const { brochure } = project;
const shareOptions = {
title: 'Download Brochure',
url: brochure
}
return (
<View>
<Text style={styles.infoTitle}>Share: </Text>
<TouchableOpacity onPress={() => this.onSharePress(shareOptions)}>
<Icon style={{paddingLeft: 10, paddingTop: 10}}name="md-share" size={30} color="black"/>
</TouchableOpacity>
</View>
)
}
}
You're not passing shareOptions to your share method, thus it is undefined.
There are many ways you could refactor your code, below you can see a more viable approach.
Since your render function used none of the logic above your return statement, I have simply migrated all of that into the onSharePress function, naturally if these differ, then you would want to pass it in via a parameter.
export default class Screen extends Component {
onSharePress = () => {
const project = this.props.navigation.getParam('project', null);
let { brochure } = project;
const shareOptions = {
title: 'Download Brochure',
url: brochure
}
Share.share(shareOptions);
}
render() {
return (
<View>
<Text style={styles.infoTitle}>Share: </Text>
<TouchableOpacity onPress={this.onSharePress>
<Icon style={{paddingLeft: 10, paddingTop: 10}}name="md-share" size={30} color="black"/>
</TouchableOpacity>
</View>
)
}
}

Single instance of component react native

I want to make a component where it renders a modal.
This component should have states{Key(integer),ImageLink(string),Visible(bool)}.
I am using flatlist. I want to render the component's modal on flatlist parent but component. States changes upon touch on flatlist child.
For example:
Modal Component which means to be single instance
import React from "react";
import {
View,
Modal,
Text,
StyleSheet,
TouchableHighlight,
Platform
} from "react-native";
export default class MySingleInstanceModal extend Component{
constructor(props) {
super(props);
this.state = {
Visiable: props.Visiable, \\Bool For turning Modal On or Off
ImageLink: props.ImageLink, \\String Image Online Link
Key: props.PostKey,\\integer Key
};
}
NextImage = (Current,Link )=> {
this.setState({ ImageLink: Link,Key:Current+1 });
};
ToggleMeOff = () => {
this.setState({ TurnMeOn: false });
};
ToggleMeOn = (MyKey,MyLink) => {
this.setState({ TurnMeOn: true,ImageLink: MyLink,Key:MyKey });
};
PrevImage = (Current,Link )=> {
this.setState({ ImageLink: Link,Key:Current-1 });
};
render() {
return (
<View>
<Modal
animationType="slide"
transparent={false}
visible={this.state.TurnMeOn}
>
<View style={{ marginTop: 22 }}>
<View>
<Text>Hello World!</Text>
<TouchableHighlight onPress={this.ToggleMeOff}>
<Text>Hide Modal</Text>
</TouchableHighlight>
<Image
source={{ uri: this.state.ImageLink }}
resizeMethod={"resize"}/>
</View>
</View>
</Modal>
</View>
);
}
}
Calling In Flatlist Parent:
render() {
return (
<View style={Style1.container}>
<MySingleInstanceModal/> // Here I want to call render
<FlatList
data={data}
initialNumToRender={4}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
onEndReached={this._reachedEnd}
refreshing={isRefreshing}
onEndReachedThreshold={0.5}
onRefresh={this._refreshdata}
ListFooterComponent={this.renderFooter}
/>
</view>)
}
And want to change states of MySingleInstanceModal in flatlist items(flatlist child)
somewhere in the rendering of flatlist child item
render(){
return (
...
<TouchableHighlight onPress={() =>
MySingleInstanceModal.ToggleMeOn(this.state.Link,this.state.Key)}>
<Text>Open Modal For Me</Text>
</TouchableHighlight>
...
)
}
Which means component will render at parent but its states will be controlled by the child(Every flatlist item)

Why won't my objects display its menu item?

I'm trying to figure out why Match and History aren't showing up whenever I slide my <Drawer/>. I've looked around a lot throughout the web and SO but can't find anything pertaining to this.
Here's SideMenu.js file:
import React, {Component} from 'react';
import { Text, View} from 'react-native';
import {List, ListItem, Header} from 'react-native-elements';
import Container from "native-base/src/theme/components/Container";
export default class SideMenu extends Component {
constructor(props) {
super(props);
}
render() {
let list = [{
title: "Match",
onPress: () => {
this.props.navigator.replace("Match")
}
}, { // 2nd menu item below
title: "History",
onPress: () => {
this.props.navigator.replace("History")
}
}];
return(
<Container theme={this.props.theme}>
<Header/>
<View>
<List dataArray={list} renderRow={(item) =>
<ListItem button onPress={item.onPress.bind(this)}>
<Text>{item.title}</Text>
</ListItem>
}/>
</View>
</Container>
);
}
}
Here's AppContainer.js file:
import React, {Component} from 'react';
import {Navigator} from 'react-native-deprecated-custom-components';
import Drawer from "react-native-drawer-menu";
import SideMenu from './components/sideMenu';
export default class AppContainer extends Component {
constructor(props) {
super(props);
this.state = {
toggled: false,
store: {}, // holds data stores
theme: null
}
}
toggleDrawer() {
this.state.toggled ? this._drawer.close() : this._drawer.open();
}
openDrawer() {
this.setState({toggled: true});
}
closeDrawer() {
this.setState({toggled: false});
}
renderScene(route, navigator) { // current route you want to change to, instance of the navigator
switch(route) {
default: {
return null;
}
}
}
// handles how our scenes are brought into view
configureScene(route, routeStack) {
return Navigator.SceneConfigs.PushFromLeft; // pushes new scene from RHS
}
render() {
return(
<Drawer
ref = {(ref) => this._drawer = ref}
type = 'default' // controls how menu appears on screen, pushes content to the side
content = {<SideMenu navigator={this._navigator} theme={this.state.theme}
/>}
onClose={this.closeDrawer.bind(this)}
onOpen={this.openDrawer.bind(this)}
openDrawerOffset={0.9}
>
<Navigator
ref={(ref) => this._navigator = ref}
configureScene={this.configureScene.bind(this)}
renderScene={this.renderScene.bind(this)}
/>
</Drawer>
);
}
}
First of all there's no such property as dataArray in ListView component. You need to create data source first and pass it to dataSource property. Look at the example in the DOCUMENTATION
Looking at the Lists API for react-native-elements https://react-native-training.github.io/react-native-elements/API/lists/
Examples using ListItem are using title prop for setting the title. Maybe try returning this instead from SideMenu render
return(
<Container theme={this.props.theme}>
<Header/>
<View>
<List>
{
list.map((item, i) => (
<ListItem onPress={item.onPress} key={i} title={item.title}/>
))
}
</List>
</View>
</Container>
);

react-native limit List items

i am using Flatlist from react-native and ListItem from react-native-elements,
i want to initially limit the number of list-items that are loaded on the screen.Otherwise it loads all the items that i have initially .
Suppose i have 300 list items but initially i only want to load 10 items ,instead of 300.
MY CODE:
import React, { Component } from 'react'
import {
FlatList
} from 'react-native'
import {Avatar,Tile,ListItem} from 'react-native-elements'
export default class Login extends Component{
constructor(props) {
super(props);
this.state = {
data:[],
dataSource: []
};
}
renderList(item,i){
return(
<View>
<ListItem
subtitle={
<Avatar
small
rounded
source={{uri: "https://s3.amazonaws.com/uifaces/faces/twitter/ladylexy/128.jpg"}}
/>
{<Text>{item.body}</Text>}
}
/>
<View>
)
}
render(){
return(
<View>
<List>
<FlatList
data={this.state.data}
keyExtractor={item => item.id}
renderItem ={({item,index}) => this.renderList(item,index)}
/>
</List>
</View>
)
}
}
Basically, what you need is to implement sort of pagination. You can do it by using onEndReached and onEndReachedThreshold(for more details look here) of FlatList to load more data when user reaches the end of list.
You can change your code like so:
import React, { Component } from 'react';
import { FlatList } from 'react-native';
import { Avatar, Tile, ListItem } from 'react-native-elements';
const initialData = [0,...,299]; //all 300. Usually you receive this from server or is stored as one batch somewhere
const ITEMS_PER_PAGE = 10; // what is the batch size you want to load.
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
data: [0,..., 9], // you can do something like initialData.slice(0, 10) to populate from initialData.
dataSource: [],
page: 1,
};
}
renderList(item, i) {
return (
<View>
<ListItem />
</View>
);
}
loadMore() {
const { page, data } = this.state;
const start = page*ITEMS_PER_PAGE;
const end = (page+1)*ITEMS_PER_PAGE-1;
const newData = initialData.slice(start, end); // here, we will receive next batch of the items
this.setState({data: [...data, ...newData]}); // here we are appending new batch to existing batch
}
render() {
return (
<View>
<FlatList
data={this.state.data}
keyExtractor={item => item.id}
renderItem={({ item, index }) => this.renderList(item, index)}
onEndReached={this.loadMore}
/>
</View>
);
}
}

Categories