manipulate state of a sibling component - react-native

component A
render(){
<View>
{this.renderB()}
{this.renderC()}
</View>
}
component B
super(props){
this.state={text: (this.props.text) ? this.props.text : '' }
}
render(){
}
component C
super(props){
}
render(){
<View>
<TouchableHighlight onPress={
...here I want to modify text state of component B
}></TouchableHighlight>
</View>
}
Is it possible to modify state of sibling like so? or should I move text properties here to component A?

When you need to share state between components, move that state up to their common parent and push them down through props.
Here's the gist of what I'm getting at. Obviously, you'd need to pass up actual values.
class ComponentA extends React.Component{
constructor(props){
super(props);
this.state = {
text: '',
}
}
render(){
return (
<View>
<ComponentB text={this.state.text}>
<ComponentC onPress={(value) => this.setState({text: value})}>
</View>
)
}
}
class ComponentB extends React.Component{
render(){
return(
<Text>{this.props.text}</Text>
)
}
}
class ComponentC extends React.Component{
render(){
return(
<View>
<TouchableHighlight onPress={this.props.onPress} />
</View>
)
}
}

Related

unable to update parent from child

The included code is almost running. I'm trying to restart the count where it left off when I toggle the device. I'm getting the following error message:
Warning: Functions are not valid as a React child. This may happen if you
return a Component instead of <Component /> from render. Or maybe you meant
to call this function rather than return it.
here's what I was attempting:
1)pass as this.props.count class App this.state.count (this creates the starting point of the counter
2) pass a callback function from APP to COUNTER that will update APP.state.count (I do this inside of COUNTERS Inc method)
NOTE: it's a little tricky to get ignorewarnings working if you don't have the right dependencies installed. lines 3, 4 and 5 can be deleted
import React from 'react';
import {Button, StyleSheet, Text, View } from 'react-native';
import ignoreWarnings from 'react-native-ignore-warnings';
ignoreWarnings(['Warning: componentWillMount is deprecated',
'Warning: componentWillReceiveProps is deprecated'])
class Count extends React.Component {
shouldComponentUpdate(nextProps,nextState){
if(nextProps.count % 2 === 0)return true
else return true
}
render(){
return(
<Text style={styles.count}>{this.props.count}</Text>
)
}
}
class Counter extends React.Component {
constructor(props){
super(props)
this.state={
count: this.props.count,
}
console.log(this)
}
componentDidMount(){
this.interval=setInterval(this.inc,1000)
}
componentWillUnmount(){
clearInterval(this.interval)
}
inc=()=>{
//console.log(thisate)
this.setState(prevState =>({
count: prevState.count + 1,
}))
this.props.resetCount(this.state.count)
}
render() {
return (
<View>
<Count count={this.state.count}/>
</View>
);
}
}
export default class App extends React.Component {
constructor(){
super()
this.state={
show:true,
count:0,
}
}
toggle=()=> this.setState(prevState => ({
show: !prevState.show
}))
resetCounter(count){
this.setState({count: Count})
}
render(){
console.log(this.state)
if(this.state.show){
return(
<View style={styles.container}>
<Button title='toggle' onPress={this.toggle}/>
<Counter
count={this.state.count}
resetCount={(count)=>{this.resetCounter(count)}} />
</View>
)
}else{
return(
<View style={styles.container}>
<View style={styles.container}>
<Button style={styles.count} title='toggle' onPress={this.toggle}/>
<Text style={styles.count}> </Text>
</View>
</View>
)
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'lightgrey',
alignItems: 'center',
justifyContent: 'center',
},
count:{
fontSize:48
}
});
First problem i see, and i think the warning come from here, is you resetCounter function. You pass "Count" (a component) to the state. I think you would like to pass the argument : count. You could do it simply like this so there is not mistake :
resetCounter(count){
this.setState({count})
}
Second thing is your callback way. You should do it like this :
export default class App extends React.Component {
constructor(){
super()
this.resetCounter = this.resetCounter.bind(this);
this.state={
show:true,
count:0,
}
}
resetCounter(count){
this.setState({count: Count})
}
render(){
...
return(
<View style={styles.container}>
<Button title='toggle' onPress={this.toggle}/>
<Counter
count={this.state.count}
resetCount={this.resetCounter} />
</View>
...
)
}
}
It's a lot better for performance and for reading.
Hope it help !
just a typo! yureka.
resetCounter(count){
this.setState({count: Count})
}
needs to be:
resetCounter(count){
this.setState({count: count})
}

How to pass children to react native ViewPager?

I'm quite new to react-native. Here Card is a view component having nothing special but text view with dimensions as flex: 1 I've my App.js as:
export default class App extends React.Component {
constructor(props: props){
super(props);
this.state = {
};
}
render() {
return (
<View style={styles.container}>
<ViewPager style={styles.pager} children={Card,Card,Card} count={3} height={100} width={100} selectedIndex={0} initialPage={0}>
</ViewPager>
</View>
);
}
}
I'm using the F8 app ViewPager which is made for both ViewPager & ScrollView for Android & iOS respectively. Which is as here (not inserting code here to keep it clean): ViewPager Component In F8 App
So what I need to know is how to pass a children to the ViewPager from my App.js
I'm not sure this is what you're looking for or what? Hope it will help you for some idea.
App.js passing value as View and Text
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<ViewPager style={styles.pager}>
// Children Array or any View as you prefer //
<Card>
<View>
<Text>Hello</Text>
</View>
</Card>
/////// End Block /////
</ViewPager>
</View>
);
}
}
ViewPager.js get value as props from App.js
export default class ViewPager extends React.Component {
render(){
return(
<View>
// these all props that pass from APP component
{this.props.children}
</View>
);
}
}

React Native - Error navigating to child components

I am able to define the initial route(Home) and the app navigates to that route. Inside Home I am calling another component called BoxLists which is displayed as expected. The issue I am having is when calling another component called StationOne from inside BoxLists.
I am getting the following error: uncaught error: undefined is not an object (evaluating 'this.props.navigator.push'
So the question is: How can I navigate from BoxLists to StationOne?
Note: I am planning to navigate to additional components(StationOne, StationTwo, StationN+1) from BoxLists.
Here is the code although you can go to RNPlayground at https://rnplay.org/apps/rLB5HQ. Thanks!
class App extends React.Component {
navigatorRenderScene(route,navigator){
if (route.title == "Home")
{
return( <Home navigator={navigator} /> );
}
if (route.title == "StationOne")
{
return( <StationOne navigator={navigator} /> );
}
}
render() {
return (
<Navigator
initialRoute = {{ title: "Home" }}
renderScene = {this.navigatorRenderScene.bind(this)}
/>
);
}
}
class Home extends React.Component {
render() {
return (
<View style={{flex: 1}}>
<View style={styles.header}>
<Text style={styles.headerText}>AdView</Text>
</View>
<BoxLists author="station one" navigator={navigator} />
</View>
);
}
}
class BoxLists extends React.Component {
_goToStation(){
this.props.navigator.push({
title: 'StationOne'
});
}
render() {
return (
<View>
<Text>You are in BoxList. The passed prop is: {this.props.author}</Text>
<TouchableHighlight onPress={this._goToStation.bind(this)}>
<Text>Press here to go to StationOne</Text>
</TouchableHighlight>
</View>
);
}
}
class StationOne extends React.Component {
render() {
return (
<View style={{flex: 1}}>
<Text> This is station one </Text>
</View>
);
}
}
class Home extends React.Component {
render() {
return (
<View style={{flex: 1}}>
<View style={styles.header}>
<Text style={styles.headerText}>AdView</Text>
</View>
<BoxLists author="station one" navigator={this.props.navigator} />
</View>
);
}
}
You need to pass this.props.navigator for the BoxLists component as shown above

How to use onPress on a custom component?

Let's assume I have this custom component:
export default class Button extends Component {
render(){
return(
<TouchOpacity>
<Text> Button </Text>
</TouchOpacity>
)
}
}
And I use it in a parent component like this :
export default class MainPage extends Component {
render(){
return(
<Button onPress={ this.doSomething }></Button>
)
}
}
For some reason (unknown to me at least) this onPress even won't happen.
I'm pretty new to react-native btw. I believe I must find a way to enable this kind of event handling.
Is it possible to get a small example how to achieve that based on my examples above ?
So, just found out how to handle this.
export default class Button extends Component {
constructor(props){
super(props)
}
render(){
return(
<TouchableOpacity
onPress={this.props.onPress}
>
<Text> Button </Text>
</TouchableOpacity>
)
}
}
and
export default class MainPage extends Component {
render(){
return(
<Button onPress={ this.doSomething }></Button>
)
}
}
Long story short: since the onPress I'm passing is a prop in the MainPage, I'm passing it a function (this.doSomething) which later on is activated in Button's onPress.
Nick's answer is right.Along with that if you want to call separate function for both child and parent component then you can use onPressOut. This will help to manage state of componant
export default class Button extends Component {
constructor(props){
super(props)
}
onClickListen = () => {
if (this.state.isSelected === false) {
this.setState({isSelected:true});
isSelectedPass=true;
}
else {
this.setState({isSelected:false});
isSelectedPass=false;
}
}
render(){
return(
<TouchableOpacity
onPress={this.props.onPress} onPressOut={this.onClickListen}
>
<Text> Button </Text>
</TouchableOpacity>
)
}
}
export default class MainPage extends Component {
render(){
return(
<Button onPress={ ()=>this.doSomething }></Button>
)
}
}

loading/importing contents of Modal from another js (class) file in react-native

My modal displays an input form. I want to import contents of my Modal from another js file for keeping the main code shorter. I am actually able to import contents of my Modal from another class file by calling component's class name as jsx tag, but in this case I cannot pass state variables of main component to inner component of the modal or vice versa. And, I don't know if it is possible to receive data from the modal in this case. I know that I could use navigator with passProps, but I want to use just a modal for this purpose. For instance:
this is main Component:
class Main extends React.Component {
constructor(props){
super(props);
this._showAddNewModal = this._showAddNewModal.bind(this);
this.state = {
addNewShow: false,
mytext: '' // this should be updated through Modal.
}
}
render(){
return (
<TouchableHighlight onPress={() => {this._showAddNewModal();}}>
<Text> Show my modal </Text>
</TouchableHighlight>
<Modal visible={this.state.addNewShow}>
<MyModalContents />
</Modal>
);
}
_showAddNewModal(){
this.setState({addNewShow: true});
}
}
this is the component to be displayed in the modal:
class MyModalContents extends React.Component { // extends Modal?
constructor(props){
super(props);
this.state = {mytext: ''}
}
render(){
<View>
<TextInput onChangeText={(text) => this.setState({mytext: text})} />
</View>
}
}
I can't even close the modal because the state of 'addNewShow' is not accessible from MyModalContents. Any help will be appreciated.
You can pass props to a child component by cloning it with React.cloneElement. Here's an example of how you could use it with your modal:
class Main extends React.Component {
constructor(props){
super(props);
this.state = {
mytext: '' // this should be updated through Modal.
}
}
_showAddNewModal(){
this.refs.modal.show();
}
render(){
return <View>
<TouchableHighlight onPress={this._showAddNewModal}>
<Text> Show my modal </Text>
</TouchableHighlight>
<Modal parent={this} ref="modal">
<MyModalContents />
</Modal>
</View>
}
}
Modal
class Modal extends React.Component {
constructor(props){
super(props);
this.state = {
visible: false,
}
}
show() {
this.setState({visible: true});
}
close(){
this.setState({visible: false});
}
render(){
return <View style={{opacity: this.state.visible ? 1 : 0}} pointerEvents={this.state.visible ? 'auto' : 'none'}>
{/* can pass props with second argument */}
{React.cloneElement(this.props.children, {
parent: this.props.parent,
modal: this
})}
</View>
}
}
MyModalContents
class MyModalContents extends React.Component {
constructor(props){
super(props);
}
_updateModalState() {
const self = this;
// will update the "Main" component state as props are passed through modal
this.props.parent.setState({myText: 'Updated Text!'}, () => {
self.props.modal.close();
});
}
render(){
return <View>
<TouchableHighlight onPress={this._updateModalState}>
<Text> Update Modal State </Text>
</TouchableHighlight>
</View>
}
}