React Native - Rerunning the render method - react-native

I have a file here that defines an icon for the title.
static navigationOptions = ({ navigation }) => {
return {
headerRight: () => (<HomeHeaderIcon/>)
}
};
HomeHeaderIcon.js
export default class HomeHeaderIcon extends Component {
async componentDidMount(){
const token = await AsyncStorage.getItem('token');
this.setState({token});
}
state={
token:null
};
render() {
return (
<View>
{
this.state.token ===null
?
(
<TouchableOpacity
onPress={() => (NavigationService.navigate("LogStack"))}>
<Icon name="ios-power" size={30} style={{color: "white",marginRight:wp("5%")}}/>
</TouchableOpacity>
)
:
(
<TouchableOpacity
onPress={() => (NavigationService.navigate("Profile"))}>
<Icon name="ios-home" size={30} style={{color: "white",marginRight:wp("5%")}}/>
</TouchableOpacity>)
}
</View>
);
}
}
The system works exactly as I want. If there is a token, I say icon1 or icon2 show. The problem is I do this in componentDidMount, the icon does not change without refreshing the page. How do I render it again?

componentDidMount is called, as the name suggests, just once, when the component is mounted. Use componentDidUpdate to decide how your component behaves based on what piece of props or state has changed.
Read the documentation for more information regarding lifecycle methods.

Related

How to update a stack navigator if its properties change?

The situation is the following, suppose I have this component.
function HomeScreen({ navigation: { navigate } }) {
const [data, setData] = useState(somedata)
return (
<View>
<Text>This is the home screen of the app</Text>
<Button
onPress={() =>
navigate('Profile', { name: data.name})
}
title="Go to Brent's profile"
/>
</View>
);
}
This component has a function that automatically updates the state when it changes in the database, (which I did not place, since it is only an example) and it works correctly, because when printing from the console, I realize that the component " HomeScreen" is rendered again, the problem is that when I navigate to the "Profile" component and update in the database, the "Profile" component is not rendered again or update then, however if the "HomeScreen" component is updated. How can I do to that somehow send a signal to the "Profile" component and it can be updated with the data from the database?
You need updated data and for that
function HomeScreen({ navigation: { navigate } }) {
const [data, setData] = useState(somedata);
useEffect(()=>{
//Console.log(data);
// Here you'll get updated data and solve your issue.
},[data]);
return (
<View>
<Text>This is the home screen of the app</Text>
<Button
onPress={() =>
navigate('Profile', { name: data.name})
}
title="Go to Brent's profile"
/>
</View>
);
}

How can I hide/show components by touching not button but screen on React Native?

I'm learning React Native for the first time. I want to implement a function to show/hide the component by touching the screen, not a specific button.
(Please check the attached file for the example image.)
enter image description here
In this code, I've tried to make a function. if I touch the screen (<View style={style.center}>, then show/hide the renderChatGroup() and renderListMessages() included in <View style={style.footer}>. The source code is below.
In my code, it works. However, the two <View> tag is not parallel. the footer view is center View's child.
I want to make them parallel. but I couldn't find the contents about controlling another <View> tag, not a child. In this code, I used setState, then I couldn't control another the below <View>.
Of course, I tried Fragment tag, but it didn't render anything.
How could I do implement this function? Please help me!
export default class Streamer extends React.Component {
constructor(props) {
super(props);
this.state = {
isVisibleFooter: true,
};
}
renderChatGroup = () => {
const { isVisibleFooter } = this.state;
if (isVisibleFooter) {
return (
<ChatInputGroup
onPressHeart={this.onPressHeart}
onPressSend={this.onPressSend}
onFocus={this.onFocusChatGroup}
onEndEditing={this.onEndEditing}
/>
);
}
return null;
};
onPressVisible = () => {
const { isVisibleFooter } = this.state;
this.setState(() => ({ isVisibleFooter: !isVisibleFooter }));
};
render() {
return (
<SafeAreaView style={styles.container}>
<SafeAreaView style={styles.contentWrapper}>
<View style={styles.header} />
<TouchableWithoutFeedback onPress={this.onPressVisible}>
<View style={styles.center}>
<View style={styles.footer}>
{this.renderChatGroup()}
{this.renderListMessages()}
</View>
</View>
</TouchableWithoutFeedback>
</SafeAreaView>
</SafeAreaView>
);
}
}
Firstly I would highly recommend you use react native with functional components and React Hooks as they alternative will soon will be deprecated.
Since onPress is not available on the View Component, you would need to replace it with TouchableWithoutFeedback as you have already done in your code.
For Showing/Hiding a view you would need to use a conditional operator.
export default class Streamer extends React.Component {
constructor(props) {
super(props);
this.state = {
isVisibleFooter: true,
};
}
renderChatGroup = () => {
const { isVisibleFooter } = this.state;
if (isVisibleFooter) {
return (
<ChatInputGroup
onPressHeart={this.onPressHeart}
onPressSend={this.onPressSend}
onFocus={this.onFocusChatGroup}
onEndEditing={this.onEndEditing}
/>
);
}
return null;
};
onPressVisible = () => {
this.setState(() => ({ isVisibleFooter: !isVisibleFooter }));
const { isVisibleFooter } = this.state;
};
render() {
return (
<SafeAreaView style={styles.container}>
<SafeAreaView style={styles.contentWrapper}>
<View style={styles.header} />
<TouchableWithoutFeedback onPress={this.onPressVisible}>
<View style={styles.center}>
{isVisibleFooter && <View style={styles.footer}>
{this.renderChatGroup()}
{this.renderListMessages()}
</View>}
</View>
</TouchableWithoutFeedback>
</SafeAreaView>
</SafeAreaView>
);
}
}
Here you can see i have replaced
<View style={styles.footer}>
{this.renderChatGroup()}
{this.renderListMessages()}
</View>
with
{isFooterVisible && <View style={styles.footer}>
{this.renderChatGroup()}
{this.renderListMessages()}
</View>}
stating that to only display the Footer View when
const isFooterVisible = true;

How to navigate through a function React Native

trying to navigate to a screen after a function is called. The navigation works perfectly well when rendered in the component but not when the function is called and its conditions are met. I've tried passing navigation but that does not work. Why does React Navigation not work directly when outside render()?
onSubmit = () => {
const { base64URI } = this.props
const { captionData } = this.state
if (base64URI !== null && captionData !== null ) {
console.log('post both image data and caption data as type photo')
this.addPhoto(base64URI, captionData);
navigate.navigation('Vault') //navigation not recognised
} else {
console.log('no data')
}
}
render() {
return(
<View style={styles.headerPost}>
<TouchableOpacity style={{position: 'absolute'}} onPress={() => this.props.navigation.goBack()}> // this navigation works..
<Text style={styles.cancelButton}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.shareButton} onPress={() => this.onSubmit()}> //when this function is called and conditions met, I want navigation to happen
<Text style={styles.shareText}>Share</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
You are using navigation in the wrong way.
it should be
this.props.navigation.navigate('Vault')

How to create a custom alert using Redux ? (Warning: Cannot update during an existing state transition)

I want, instead of using the default Alert.alert method, to create my own so that I could change the background of my Alert, whether it's successful or not. To do so, I use a Modal, which put in my root component, App.js (so that the modal can appear on each screen) :
App.js
// ...
const Navigation = createAppContainer(MainNavigator);
// Render the app container component with the provider around it
class App extends React.Component {
render() {
return (
<Provider store={store}>
<Navigation />
<CustomAlert /> {/* <--- here */}
</Provider>
);
}
}
I do so because I don't want to place my <CustomAlert /> component on each Screen that I use. If someone has another approach I'll take it.
CustomAlert.js
// ... (imports)
class CustomAlert extends Component {
render() {
const { customStyle } = this.props;
const { title, description, enabled } = this.props;
const { reinit } = this.props; // dispatch
return (
<View>
<Modal
animationType="none"
transparent
visible={enabled}
>
<View style={styles.fullScreen}>
<View style={[styles.content, customStyle]}>
<View style={{ flex: 1 }}>
<View style={styles.title}>
<Text style={{ fontWeight: 'bold' }}>{title}</Text>
</View>
<View style={styles.desc}>
<Text style={{ textAlign: 'center' }}>{`${description}`}</Text>
</View>
<View style={styles.buttons}>
<TouchableOpacity
onPress={() => {
reinit();
}}
style={styles.button}
>
<Text>OK</Text>
</TouchableOpacity>
</View>
</View>
</View>
</View>
</Modal>
</View>
);
}
}
function mapStateToProps(state) {
return {
type: state.alert.type,
title: state.alert.title,
description: state.alert.description,
enabled: state.alert.enabled,
};
}
function mapDispatchToProps(dispatch) {
return {
reinit: () => dispatch(reinitState()),
};
}
export default stylesWrapper(connect(mapStateToProps, mapDispatchToProps)(CustomAlert));
I proceed like that:
In my function that shows the alert, I simply change my redux store:
helper.js
// ...
export const infoAlert = (title, msg, type = 'error') => {
store.dispatch(setTitle(title));
store.dispatch(setDescription(msg));
store.dispatch(setType(type));
store.dispatch(setEnabled(true));
};
// ...
The behaviour is good but I have this warning :
Warning: Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state.
I suspects this has one reason between those two:
Using store.dispatch as a general function doesn't know anything about the component that called him, so this message indicates that It might rerender it (which is bad)
infoAlert is called inside a functionnal component (Redux Form), and it's state shouldn't change (something like that)
Here an example of call infoAlert (at the bottom):
const renderField = ({
input,
label,
keyboardType,
secureTextEntry,
autoCapitalize,
autoCorrect,
meta: {
touched, error, warning, active, dirty,
},
}) => (
<View>
<TextInput
style={[styles.textInput, (active) && styles.active,
(touched) && (((error) && styles.error)
|| ((warning) && styles.warning))]}
{...input}
onChangeText={input.onChange}
onBlur={input.onBlur}
onFocus={input.onFocus}
value={input.value}
keyboardType={keyboardType}
placeholder={label}
secureTextEntry={secureTextEntry}
autoCapitalize={autoCapitalize}
autoCorrect={autoCorrect}
/>
{(touched && !active && dirty) && (((error) && infoAlert('Erreur', error))
|| ((warning) && infoAlert('Attention', warning)))}
</View>
);
Do someone has an idea of how to remove this Warning ?
Do someone has another way (maybe simpler) to create a custom alert (without putting the component itself everywhere) ?
Screens

How to send data to another page in react-native

I have Main component and Bar component. I want to send some info to Bar component.
This is my code:
render() {
<View>
<View>
<Bar />
</View>
<View>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Bar', { Info:'test' }) }>
</TouchableOpacity>
</View>
<View/>
}
I cant send like this because Bar component is in this component. How Can I fix this.
Since your're in the same component ... setState is your answer
class Comp extends React.Component {
state = {
info: '',
};
render() {
const { info } = this.state;
return (
<View>
<View>
<Bar info={info} />
</View>
<View>
<TouchableOpacity
onPress={() => {
this.setState({ info: 'test' });
}}
/>
</View>
</View>
);
}
}
State There are two types of data that control a component: props and
state. props are set by the parent and they are fixed throughout the
lifetime of a component. For data that is going to change, we have to
use state.