Pass a method as a prop to the class static function - javascript

I can't solve this issue by myself. I have a Class
class WebViewScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
url: 'https://example.org',
};
}
someMethod = () => {
return 'something';
}
render() {
return (
<View style={styles.mainContainer}>
<WebView
source={{uri: this.state.url}}
/>
<StatusBar backgroundColor="white" barStyle="dark-content" />
</View>
);
}
static navigationOptions = ({navigation}) => {
return {
headerTitle: () => (
<AddressBar navigation={navigation} />
),
};
};
}
I want to access someMethod from static navigationOptions
I've tried the following without the success:
run this.someMethod()
run WebViewScreen.someMethod()
let _this outside a class, then _this = this from a WebViewScreen Class constructor
then _this.someMethod() from static navigationOptions
My question is, how can I achieve this?

You cannot access the component's state from within a static method. What you can do is keeping a navigation's parameter in sync with your local state and/or pass functions to it with
this.props.navigation.setParams({
someMethod: this.someMethod.bind(this)
})
which you can retrieve with:
static navigationOptions = ({ navigation }) => {
const someMethod = navigation.getParam('someMethod', () => null)
// ... someMethod()

There is a build-in function in React Navigation 4 called: setParams. This function could be used to set params in static navigationOptions, however in React Navigation 5 there will be a dynamic way to change the navigation. Until then you should use setParams. In your WebViewScreen component you should use it like this.
class WebViewScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
url: 'https://example.org'
};
}
componentDidMount() {
const { navigation } = this.props;
navigation.setParams({ logOut: this.someMethod });
}
someMethod = () => {
return 'log out';
};
render() {
return (
<View style={styles.mainContainer}>
<WebView source={{ uri: this.state.url }} />
<StatusBar backgroundColor="white" barStyle="dark-content" />
</View>
);
}
static navigationOptions = ({
navigation,
navigation: {
state: { params }
}
}) => {
return {
headerTitle: () => <AddressBar navigation={navigation} />,
headerRight: (
<TouchableOpacity onPress={() => params.someMethod()}>
Log out
</TouchableOpacity>
)
};
};
}
Important to note: you can only add params to the static nav, when the component is mounted!

Related

Call function with setState from other component

I have the following setup:
import {getNewImage} from '...'
export default class FirstClass extends Component {
constructor() {
super();
this.state = {
imageURL: 'www.test.com/new.jpg',
}
}
update = () => {
this.setState({
imageURL: 'www.test.com/updated.jpg',
})
}
render() {
return (
<View>
<Image
source={{ uri: this.state.imageURL }}
/>
</View>
);
}
}
import Class1 from '...'
export default class SecondClass extends Component {
render() {
return (
<TouchableOpacity onPress={() => new FirstClass().update()}>
<Class1></Class1>
</TouchableOpacity>
);
}
}
The problem is: it doesn't update the imageURL. I tried multiple things. Logging this inside of update gave back the right object. But trying to log the this.setState() gives an undefinded back.
I suppose by Class1 you mean FirstClass.
you should use the reference of the component using ref, not creating new instance of FirstClass class
checkout this code
export default class SecondClass extends Component {
private firstClass = null;
render() {
return (
<TouchableOpacity onPress={() => this.firstClass.update()}>
<Class1 ref={ref => this.firstClass = ref} />
</TouchableOpacity>
);
}
}
You can try to update state in Class1 similar to what do you want by the react reference.
But on my opinion this is non a good case and predictable behavior to change child component state from parent.
As another options you can add additional state to the SecondClass and pass it via props to child component. And inside Class1 in getDerivedStateFromProps based on that prop change state.
export default class FirstClass extends Component {
constructor() {
super();
this.state = {
isNeedToUdpate: false,
imageURL: "www.test.com/new.jpg"
};
}
static getDerivedStateFromProps(props, state) {
if (props.isNeedToUdpate !== state.isNeedToUdpate) {
return {
isNeedToUdpate: props.isNeedToUdpate,
imageURL: "www.test.com/updated.jpg"
};
}
return null;
}
render() {
return (
<View>
<Image source={{ uri: this.state.imageURL }} />
</View>
);
}
}
export default class SecondClass extends Component {
constructor() {
super();
this.state = {
isNeedToUpdateClass1: false
};
}
render() {
return (
<TouchableOpacity
onPress={() => {
this.setState({ isNeedToUpdateClass1: true });
}}
>
<Class1 isNeedToUpdate={this.state.isNeedToUpdateClass1}></Class1>
</TouchableOpacity>
);
}
}

React native: passing image path as params through 2 components

i'm trying to pass an image path down to one component via react-navigation params and from that component to a third one as a prop.
This is a chat application and the structure of the components is:
ChatsMain.js --> (click on SingleChat, passing parameters when navigating) --> SingleConversation.js --> Message
I can pass 'name' as a parameter, but not the uri of an image, not even by assigning it to variables.
The name that i see on the SingleChat is passed without problems to the correspondent conversation, but when i pass the image i get the error:
'Failed prop type: Invalid prop source supplied to Image.'
I hope it's clear enough, i don't think it's the correct way to do this, but i am new to react native!
ChatsMain.js
const imageNames = {
juf: require('../assets/juf.png'),
meester: require('../assets/meester.png'),
groep: require('../assets/groep.png'),
onderwerpen: require('../assets/onderwerpen.png')
}
export default class ChatsMain extends React.Component {
render() {
return (
<SingleChat
image={imageNames.juf}
backgroundColor={yellow}
borderColor={blue}
name='Juf Elsa'
onPress={() => this.props.navigation.navigate('SingleConversation', {name: 'Juf Elsa', image: imageNames.juf})}
/>
)
SingleConversation.js
export default class SingleConversation extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('name', 'Chat'),
headerStyle: [titleBar, { backgroundColor: yellow }],
headerTitleStyle: [title, { color: blue }]
}
}
render() {
return (
<View style={chatMainContainer}>
<ScrollView style={chatsContent}>
<Message image={({navigation}) => navigation.getParam('image', 'image')} />
</ScrollView>
</View>
);
}
}
Message.js
export default class ReceivedFirst extends React.Component {
render(
){
return(
<View style={textWithPicture}>
<View style={[chatPhotoContainer, { borderColor: yellow }]}>
<Image source={this.props.image} style={{ width: 70, height: 70}} />
.....
.....
)
You can use this.props.navigation.state.params instead this.props.navigation.getParam
export default class SingleConversation extends React.Component {
constructor(props) {
super(props);
this.state = {
image: this.props.navigation.state.params.image
};
}
...
Message image={this.state.image} />
OR
You need to get a Navigation from the props.
render() {
const { navigation } = this.props
return (
<View style={chatMainContainer}>
<ScrollView style={chatsContent}>
<Message image={() => navigation.getParam('image', 'image')} />
</ScrollView>
</View>
);
}

How do I change the theme of whole app in React-native?

I want to change the theme of the app(say background colors) by selecting from a list of colors. I've tried saving the state in a reducer and applying the state to a new page.
LoginView.js
import styles from "./styles";
class LoginView extends Component {
constructor(props) {
super(props);
this.state = {
primaryColor: theme.PRIMARY_COLOR
};
}
navigate = () => {
this.props.navigation.navigate("Home");
};
onPressGreen = () => {
theme.PRIMARY_COLOR = "green";
this.setState({ primaryColor: theme.PRIMARY_COLOR });
this.props.onPressGreenButton(theme.PRIMARY_COLOR);
};
onPressRed = () => {
theme.PRIMARY_COLOR = "red";
this.setState({ primaryColor: theme.PRIMARY_COLOR });
};
render() {
return (
<View
style={[styles.container, { backgroundColor: this.state.primaryColor }]}
>
<TouchableOpacity
style={styles.greenButton}
onPress={this.onPressGreen}
>
<Text>Green</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.redButton} onPress={this.onPressRed}>
<Text>Red</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.navigate}>
<Text>Home</Text>
</TouchableOpacity>
</View>
);
}
}
function mapDispatchToProps(dispatch) {
return {
onPressGreenButton: color => dispatch(loginActions.saveColor(color))
};
}
export default connect(
null,
mapDispatchToProps
)(LoginView);
HomeView.js
class HomeView extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View style={[styles.container, { backgroundColor: this.props.color }]}>
<Text>Home</Text>
</View>
);
}
}
function mapStateToProps(state) {
return {
color: state.loginReducer.color //color saved in reducer
};
}
export default connect(
mapStateToProps,
null
)(HomeView);
In HomeView.js file instead of applying backgroundcolor in the way I did, how to include it inside styles.container. Is there any way to access function mapStateToProps inside styles.js I've imported. I've used redux to save the state permanently.
you can use redux outside of react component like styles.js
by store.getState() API in redux
but I think the best way to handle this is to create a wrapper component and apply them to it then use it everywhere you want
class MasterView extends Component {
render() {
return (
<View style={[styles.container, { backgroundColor: this.props.color }]}>
{this.props.children}
</View>
);
}
}
function mapStateToProps(state) {
return {
color: state.loginReducer.color //color saved in reducer
};
}
export default connect(
mapStateToProps,
null
)(MasterScreen);
then on each screen, you want you can use it for example
class HomeView extends Component {
constructor(props) {
super(props);
}
render() {
return (
<MasterView>
<Text>Home</Text>
</MasterView>
);
}
}
another way is in styles.js
import store from '../store'
const containerColor=store.getState().loginReducer.color
const styles = StyleSheet.create({
container: {
backgroundColor:containerColor
},
}
export default styles

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.

React Native Pass array from child to parent component

I have two components and i am trying to pass array state on back button to parent component but its not showing any data.
Screen1.js
class Screen1 extends Component {
constructor(props) {
super(props);
this.state = {
selectedRecord: []
};
}
updateData = (data) => {
this.setState({selectedRecord: data})
}
render() {
const {container} = styles;
return (
<View style={container}>
<Button onPress={() => alert(this.state.selectedRecord)}>
Show Value
</Button>
</View>
);
}
}
I created a method on Screen2.js
class Screen2 extends Component {
constructor(props) {
super(props);
this.state = {
record: [1, 2, 3, 4, 5]
};
}
backStock() {
this.props.navigation.state.params.updateData(this.state.record);
this.props.navigation.goBack()
}
render() {
const {container} = styles;
return (
<View style={container}>
<Button onPress={() => this.backStock()} transparent>
<Icon name='arrow-back'/>
</Button>
</View>
);
}
}
And backStock() method runs when i click on my back button. But when i tried to print value in console it was empthy. Am i missing something, is there a smooth way to pass states onback method?

Categories