Complete explanation about Context API in react native - javascript

I'm a little bit confused about how Context API works
as the docs said about Context Provider:
Accepts a value prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers. Providers can be nested to override values deeper within the tree.
I just start to try a simple code like this:
//App.js
export default class App extends React.Component {
constructor(props) {
super(props);
this.changeColor=(color, value)=>{
this.setState({[color]:value})
}
this.state={
changeColor:this.changeColor,
red:0,
green:0,
blue:0,
}
}
render() {
console.disableYellowBox = true;
return (
<ThemeContext.Provider value={this.state}>
<InitialScreen/>
</ThemeContext.Provider>
);
}
}
//InitialScreen.js
export default class Login extends Component {
render() {
return (
<ThemeContext.Consumer>
{({red, green, blue, changeColor})=>(
<View style={{flex:1}}>
<View style={{flexDirection:'row', justifyContent:'space-between'}}>
<Text>Red: </Text>
<Slider
style={{width:'80%'}}
minimumValue={0}
maximumValue={255}
step={1}
value={red}
onValueChange={(e)=>{changeColor('red', e)}}
/>
</View>
<View style={{flexDirection:'row', justifyContent:'space-between'}}>
<Text>Green: </Text>
<Slider
style={{width:'80%'}}
minimumValue={0}
maximumValue={255}
step={1}
value={green}
onValueChange={(e)=>{changeColor('green', e)}}
/>
</View>
<View style={{flexDirection:'row', justifyContent:'space-between'}}>
<Text>Blue: </Text>
<Slider
style={{width:'80%'}}
minimumValue={0}
maximumValue={255}
step={1}
value={blue}
onValueChange={(e)=>{changeColor('blue', e)}}
/>
</View>
<View style={[GlobalStyles.Center, {flex:1, backgroundColor:'rgb('+red+', '+green+', '+blue+')'}]}>
</View>
</View>
)}
</ThemeContext.Consumer>
);
}
}
//themeContext.js
import React from 'react';
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
})
I don't know what's the meaning of Object inside React.createContext({...}), i can pass this.state in Provider value props that's mean I don't need to define anything in React.createContext({...}) AFAIK,
or maybe I'm doing something wrong so I'm out of Context function itself?

You're absolutely right, you don't need to provide anything in React.createContext in order to use it. The data you provided in createContext is merely default value and will be override as you set Context.Provider later on. However, I strongly recommend you to always provide a default value because of the following reasons:
By doing so you can think ahead of what kind of data your context would serve, hence help you to understand the structure of your code better. This habit would help you in long run
It gives whatever IDE you're using (Visual Studio for example) a clue of your Context data and it would give better hints as you code

Related

React Native Styled Components how to pass non specific styles as props for re usable components

Given the following simple component example which uses styled components for the Pressable:
const StyledPressable = styled.Pressable = props => props.buttonStyle
const Icon: FC<{buttonStyle: string}> = ({buttonStyle}) => {
return (
<StyledPressable buttonStyle={buttonStyle} >
<SomeIconComponent/>
</StyledPressable>
)
}
I would like to create a reusable component which takes in style props while still using styled components. Normally using the vanilla react native styles, this is really simple one would just pass in the style object as a prop an use it as a value in the necessary component. How would i achieve this behavior using styled components? my initial guess is that the buttonStyle has to be a string in the same format as styled components, but how would i make it so that the style which is declared inside the '' of lets say StyledPressable in this example is equal to the passed buttonStyle prop?
Since i am learning styled components, i am very open to any other way to achieve this behavior while using styled components.
import styled from "styled-components/native"
const Pressable = styled.Pressable(props => (props.buttonStyle))
export default function App() {
return (
<View style={styles.container}>
<Pressable buttonStyle={{ backgroundColor: "pink" }}>
<Text>This is button</Text>
</Pressable>
</View>
);
}
Inder's answer using some Typescript
import styled from "styled-components/native"
interface PressableProps {
buttonStyle?: CSSObject
}
const Pressable = styled.Pressable<PressableProps>({ buttonStyle }) => buttonStyle)
export default function App() {
return (
<View style={styles.container}>
<Pressable buttonStyle={{ backgroundColor: "pink" }}>
<Text>This is button</Text>
</Pressable>
</View>
);
}

typeError: Cannt read property 'goBack' of undefined

So the scenario is, I want to implement a GoBack Icon at the top of my app,that leads back to previous page. I am using stack navigator and disabled the header. So I need a go back button. I decided to make a component for that, here is my code,
import { Ionicons } from '#expo/vector-icons';
function GoBack(){
return (
<Ionicons onPress={()=>this.props.navigation.goBack()} name="md-arrow-back" size={24} color="#0c85f3" />
);
}
export default GoBack;
if I do it like this then an it shows me a typeError: Cannt read property 'goBack' of undefined.but if I put onPress as props and implement the same line of code onPress={()=>this.props.navigation.goBack()} it works perfectly.
I can not apply onPress props everywhere. Its a app with a lot of screens. How do I apply it in the component itself?
I think I am in lack of deep understanding of React navigation. Please help me understand the solution too.
Here is how I am using the GoBack Component:
import React, { Component } from 'react';
import {View, StyleSheet, Text, FlatList} from 'react-native';
import TestRoomtData from '../../../testData';
import HistoryCard from '../../../components/cards/historyUserCard';
import GoBack from '../../../shared/goBackButton';
class UserHistory extends Component{
render(){
return(
<View style={styles.container}>
<View style={{flexDirection:"row",}}>
<GoBack />
<Text style={styles.title}>History</Text>
</View>
<Text style={styles.title01}>Past Patients</Text>
<FlatList
data={TestRoomtData}
renderItem={({item})=>([
<View>
<HistoryCard
prescription={item.prescription}
diagnosis={item.diagnosis}
date={item.date}
source={{
uri: item.uri
}}
btnText01="More"
btnText02="Edit"
onPressBtn2={()=> this.props.navigation.navigate('Edit History') }/>
</View>
]
)}
/>
</View>
);
}
}
It's a functional component,
First : so you can't use this. ,
Second : you forgot to get props
function GoBack(props){ // <---- HERE
return (
<Ionicons
onPress={props.navigation.goBack} // <---- HERE
name="md-arrow-back" size={24} color="#0c85f3" />
);
}
In functional component in react, you can't use this keyword to access props.
In the current situation you have to pass navigation prop in GoBack
something like this,
function Goback(props) {
const { navigation } = props;
return (
<Ionicons
onPress={() => navigation.goBack()}
name="md-arrow-back"
size={24}
color="#0c85f3"
/>
);
}
Now, call the GoBack component,
<GoBack
navigation={{ goBack: () => goBack() }}
/>

Component function can't recognize this operator in react native

Basically, I want to call function (class method) from inside the functionComponent in react-native. Only way i can do it by passing as a props as shown in example B (image with debugging info). I want to try it like in example A (image with debugging info); Is there some way to achieve that (not using props)? Or there is whole another way to do it, any suggestion or tips or tricks would be nice. Or am i missing something.
Code for Example A.
//Example A
import React from 'react';
import { Text, View, Button } from 'react-native';
export default class RegisterScreen extends React.Component{
state = { message: "state message"};
openDialog(){
alert("hello..");
}
funcComponent({text}){
console.log(this);
console.log(this.state.message);
return(
<View>
<Text>{text}</Text>
<Button onPress={()=> this.openDialog()} title="Open"/>
</View>
);
}
render(){
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<this.funcComponent text="hello from component." />
</View>
);
}
}
Example A Debugging Report Image
Code for Example B
//Example B
import React from 'react';
import { Text, View, Button } from 'react-native';
export default class RegisterScreen extends React.Component{
state = { message: "state message"};
openDialog(){
alert("hello..");
}
funcComponent({text, openDialog, context}){
console.log(context);
console.log(context.state.message);
return(
<View>
<Text>{text}</Text>
<Button onPress={()=> openDialog()} title="Open"/>
</View>
);
}
render(){
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<this.funcComponent text="hello from component." openDialog={this.openDialog} context={this} />
</View>
);
}
}
Example B Debugging Report Image
Edit:
Ok, basically the problem is with the component, we can't just use "this" operator inside the functioncomponent coz we are using in the <this.funcComponent> (in Example A) that is why we need to pass this operator as props (which is done in Example B). In Example A "this" operator is out of the scope so that is why we need to pass as props.
Hope this is helpful to other who is facing this problem.
Edit 2: Solution for what i looking for
I found new solution for using "this" operator inside method or function, to use this operator we need to make arrow function, which makes the function inside the scope of the class.
(Basically it's a ES6 pitfall) reference: #doppio react native Flatlist navigation
Code for Example C
//Example C
import React from 'react';
import { Text, View, Button } from 'react-native';
export default class RegisterScreen extends React.Component{
state = { message: "i m state message"};
openDialog(){
alert("hello..");
}
funcComponent=({text}) => {
console.log(this);
console.log(this.state.message);
return(
<View>
<Text>{text}</Text>
<Button onPress={()=> this.openDialog()} title="Open"/>
</View>
);
}
render(){
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<this.funcComponent text="hello from component." />
</View>
);
}
}

How to set a default value for props in React native

I need to know how to set a default value for props to React Native.
I have the following code:
<View style={{ ...styles.textBox, ...props.bg }}>
<Text style={{ ...styles.pretitle, ...props.style }}>{props.pretitle}</Text>
<Text style={{ ...styles.title, ...props.style2 }}>{props.title}</Text>
<Text style={styles.introduction}>{{ '', ...props.introduction }}</Text>
</View>
If props.introduction is 0 I want to set it to empty, like: '', or to have some other value, like: 'Not set'.
Thank you
You can use defaultProps in React
export default class Example extends React.Component {
render() {
return (
<View>
<Text>{this.props.fName},{this.props.lName}</Text>
</View>
);
}
}
Example.defaultProps = {
fName: "Hello",
lName: 'world'
}
Hope this helps you. Feel free for doubts.

How to call a function in a React Native class from a different module

In my app, I have defined a default class A in module xyz.js that renders a page on my navigation stack. Depending on one of class A's state variables, the views that are rendered differ. For example, if the app is placed in an "edit mode", then an editing view is rendered in addition to the other standard views rendered when the app is not in the "edit mode". I can't figure out how to change that state variable from a different module abc.js and cause the views associated with the instantiated class A to re-render. In my module abc.js, I create the navigation stack and I have an onPress handler for a touchableHighlight button to place the app in "edit mode". In that handler, I attempt to call a function "Edit()" in class A. But the function does not seem to get invoked. It may have something to do with binding, but that concept is not something I fully understand.
Here is what I have:
Module abc.js:
import XYZ from './xyz';
import {Edit} from './xyz';
import { pencilEditButton } from './Images';
const App = createStackNavigator(
{
Home: {
screen: My App,
navigationOptions: ({ navigation }) => ({
title: 'myApp',
headerRight: (
<View>
<TouchableHighlight
onPress={() => Edit()}
underlayColor="gray">
<View>
<Image source={pencilEditButton} style={styles.navigationButtonImage} />
</View>
</TouchableHighlight>
</View>
),
}),
},
}
);
export default createAppContainer(App);
Module xyz.js:
export default class XYZ extends React.Component {
constructor(props) {
super(props);
this.state = {
editMode: false,
};
};
// Create a method to handle the press of the edit button on the navigation bar
Edit() {
console.log("editMode: ", editMode);
this.setstate({ editMode: true });
console.log("editMode: ", editMode);
alert('User wants to edit a mix!');
};
render() {
return (
<View style={styles.container}>
{ this.state.editMode === true ?
<TouchableHighlight
onPress={this._onXPressed}
underlayColor="white">
<View style={[styles.flowRight, styles.controlButton]}>
<Text style={styles.buttonText}>{'Edit Mode'}</Text>
</View>
</TouchableHighlight>
:
<TouchableHighlight
onPress={this._onYPressed}
underlayColor="white">
<View style={[styles.flowRight, styles.controlButton]}>
<Text style={styles.buttonText}>{'Non Edit Mode'}</Text>
</View>
</TouchableHighlight>
}
</View>
);
}
}
So as you can see, there is a function called "Edit()" after the constructor in class XYZ of module xyz.js. This function is called from module abc.js when the edit button is pressed. But when the edit button is pressed, the state is not updated, the alert view is not displayed, and the views are not re-rendered. How do I correctly call Edit() so that the state variable "editMode" is updated and the views are re-rendered?
If you want to follow the pattern you are using, it needs to be handles inside your 'My App' component which gets render in stack navigator. You have to use refs
Go through the following code example to find out how to call Edit function.
import XYZ from './xyz';
export default class MyApp extends React.Component {
static navigationOptions = ({ navigation }) => ({
title: 'myApp',
headerRight: navigation.state.params && navigation.state.params.edit ? (
<View>
<TouchableHighlight
onPress={() => navigation.state.params.edit()}
underlayColor="gray"
>
<View>
<Image source={pencilEditButton} style={styles.navigationButtonImage} />
</View>
</TouchableHighlight>
</View>
) : null,
})
constructor(props) {
super(props);
this.onEdit = this.onEdit.bind(this);
}
componentDidMount() {
this.props.navigation.setParams({ edit: this.onEdit });
}
onEdit() {
if (this.xyz_Ref) {
this.xyz_Ref.Edit();
}
}
render() {
return (
<View>
<XYZ ref={ref => this.xyz_Ref = ref} />
</View>
);
}
}

Categories

Resources