Make shared component with calling navigation.navigate() inside - React Native - reactjs

I want to make shared component for all screen in react native. So I can share them between main components.
See my code below, everything works but the this.props.navigation.navigation.navigate('HireJob') not working.
MyCode :
export default class MyComponent extends Component {
callAndPush = () =>{
console.log('callAndPush');
this.props.navigation.navigate('HireJob')
}
render() {
return (
<TouchableHighlight style = {{backgroundColor : 'red' , height : 30}} onPress = {() => this.callAndPush()}>
<Text>Apple</Text>
</TouchableHighlight>
);
}
}
Use of Component :
render(){
return (
<View style = {styles.scrollSty}>
<MyComponent></MyComponent>
</View>
);
}
}

it works like this, bypassing navigation prop into MyComponent.
<MyComponent {...this.props} />

Every component can be imported into other components, such as navigators. They import your scenes and navigate between them by sharing props.
To make a component and use it in different places simply create one:
export default class MyComponent extends React.Component {
render() {
return (
<Text> This is a special component </Text>
);
}
}
And in your other classes use it like this:
import MyComponent from '../path/to/MyComponent';
class AnotherComponent extends React.Component {
render() {
return (
<MyComponent />
);
}
}
Starting from React 0.14, you can create these easier using stateless components:
// A functional component using an ES2015 (ES6) arrow function:
const MyComponent = (props) => {
return <Text> This is a special component </Text>
};
You can pass data using props if you like.

Related

How to use navigation using functional component - react native

How can I use navigation using class component, the screens that I currently have on my app are functional components, and this is how I'm able to navigate from one page to another, but If try to implement this using functional comopenent it doesn't work.
export default function Activity({navigation}) {
return (
<View style={styles.MainContainer}>
<TouchableOpacity onPress={() => navigation.navigate("Home")}>
</TouchableOpacity>
</View>
)
}
How Can I implemented in here :/
I tried
this.props.navigation.navigate('Home')
and I got the following error/warning
cannot update a component while rendering a different component
export default class App extends React.Component {
render() {
return (
<View style={styles.MainContainer}>
<TouchableOpacity onPress={() => navigation.navigate("Home")}>
</TouchableOpacity>
</View>
)
}
For my navigation, I had to add at the beginning of the file this importation
import { useNavigation } from '#react-navigation/native'
And in my functional component
const navigation = useNavigation()
Like this :

How do I render a class (react component) passed as a prop?

import SomeComponent from 'Somewheere';
class MyPage {
render() {
return '<OtherComponent AcceptsSomeClass={SomeComponent} />';
}
}
in OtherComponent I want to be able to do
class OtherComponent {
render() {
return <this.props.AcceptsSomeClass open={true} someOtherProp={123}/>;
}
}
I want to be able to render SomeComponent inside OtherComponent. I know I can just pass a node or a function. But I've seen a library before that accepts a class like this and I want to pass the class so that I can control it more in OtherComponent instead of deciding how it renders in MyPage and passing it thee node/function.
In other words I want to pass a class (react component) as a prop and then be able to use it in the JSX.
What I did is that we are passing a function that renders a component, then we can call that function inside the OtherComponent to render it there.
class MyPage extends React.Component {
render() {
return <OtherComponent AcceptsSomeClass={() => <SomeComponent />} />
}
}
class OtherComponent extends React.Component {
render() {
return (
<div>
<p>Content inside OtherComponent</p>
{this.props.AcceptsSomeClass()}
</div>
)
}
}
class SomeComponent extends React.Component {
render() {
return <h1>HELLO WORLD!</h1>
}
}
ReactDOM.render(<MyPage />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'></div>
An example of which you can pass components as props is when you are dealing with HOC (higher-order-components)
I use HOC to handle HTTP requests, for instance, using a modal to pop up on the screen with the loading / error when fetching /putting data, or authentication.
I will present you with a simple example:
import React from 'react'
import Modal from 'modal' //this would be a modal covering the screen
const httpHandler = WrappedComponent => {
const wrappedComponent = props => {
//handle some logic here, coded here, or as a result from some middleware
return (
<Fragment>
<Modal>...</Modal> //handle the HTTP async stuff here, like loading,
//or authentication, or an error message
<WrappedComponent {...props} />
</Fragment>
)
}}
You can call this inside a Component like this when you export another component
//all of the component stuff above
export default httpHandler(WrappedComponent)

Update parent React component from child component

I'm using react context api to show my data everywhere and updating from everywhere I want that my data can be show on multiple screens and I can update from more than one class I need to use that globally.
When I try to update it from class profile screens nothing happen but it can be updating from class home screen.
How Can I show my data in consumer without using like this ,and show this data globally
const Context = React.createContext("default value")
global.cart = 1;
Class home screen that is context provider class
class HomeScreen extends Component<Props> {
constructor(props){
super(props);
this.state={
contextData:5}}
render() {
return (
<View>
<Context.Provider value={this.state.contextData}>
<Button title="Increment" onPress={++global.cart;
this.setState({contextData:global.cart})}/>
</Context.Provider>
<ProfileScreens/>
</View>
)
}
}
text that I need to use and show in many screens
class ProfileScreen extends Component<Props> {
render() {
return (
<View style={{}}>
<Context.Consumer>
{data=> <Text style={{fontSize:50}}>{data.toString()}</Text>}
</Context.Consumer>
</View>
);
}
}
another class which is changing the context provider data
class ProfileScreens extends Component<Props> {
constructor(props){
super(props);
this.state={contextData:5}}
render() {
return (
<View >
<Context.Provider value={this.state.contextData}>
<ProfileScreen/>
<Button title="decrementss" onPress={()=>{ ++global.cart;
this.setState({contextData:global.cart})}}/>
</Context.Provider>
</View>
);
}
}
you need to pass a callback down from HomeScreen to ProfileScreens
this callback would be called within ProfileScreens and trigger HomeScreen state change:
in HomeScreen:
...
<ProfileScreens changeHomeScreen={() => this.setState({...})}/>
...
then in ProfileScreens:
...
<Button title="decrementss" onPress={()=>{ this.props.changeHomeScreen() }}/>
...

how to pass the results of a function from one component to another in react-native?

I have a component that runs a function and returns a result but I need the rest of my components to access that data from the function. How would I be able to do that?
Here is my app.js that contains the components. This is an example but my question is how would I run a function in Camera component and then reference the data in the Display component.
export default class App extends React.Component {
render() {
return (
<View>
<Camera />
</View>
<View>
<Display />
</View>
);
}
}
You can store the data as a state in the parent component and pass it as a prop to Display, and allow Camera to alter the state through a callback (setData in the example below).
export default class App extends React.Component {
state = {
data: null,
};
render() {
return (
<View>
<View>
<Camera setData={(data) => this.setState({ data })} />
</View>
<View>
<Display data={this.state.data} />
</View>
</View>
);
}
}
const Camera = props => <Button onPress={() => props.setData(...)} />
const Display = props => <Text>{props.data}</Text>
If your Display component is dependant on Camera components data, I would suggest you add Display component as a child in Camera component.
You can achieve this by:
Keeping state for Camera component,
update the state in a function based on some activity (e.g. button click)
In your Camera component's render() method, only when you have desired data available in the state, mount Display component.
Pass the desired data to Display component via props.
e.g.
Camera component
class Camera extends React.Component {
constructor(props) {
super(props);
this.state = {
data: null
}
}
foo = () => this.setState({data: 'new_data'});
render() {
const { data } = this.state;
const dataPresent = data !== null;
return (
{
!dataPresent && (
<button value="set data" onClick={() => this.foo() />
)}
{
dataPresent && (
<Display data={data} />
)}
);
}
}
Display Component
const Display = (props) => <div> <span> { props.data } </span> </div>
If you would still like to pass/use data from one component in another component, with both components at the same level, you either need to have state for parent component or have a global store like Redux to keep data in one place and access it in Display component.
I will recommend to use redux, it simplifies stuff a lot, and do not need level up or pass state to parent/child
In your case you will need to pass props in Camera and Display component

How to use JSX spread attributes to pass arbitrary props to my controlled component?

In a controlled component, how do I pass arbitrary props to the render function? I think I need to make use of a constructor but I am getting "props is not defined" and other errors.
import * as React from 'react';
import { View } from 'react-native';
import styles from './Styles';
export default class MyView extends React.Component {
constructor(????) {
// What do I do so I can use {...props} in the render function below?
}
render() {
return (
<View style={styles.wrap} {...props}>
<View style={styles.main}>
{this.props.children}
</View>
</View>
);
}
};
I want to be able to do...
<MyView arbitraryprop="123" />
...and have arbitraryprop get passed to MyView::render().
The default constructor of <Component> does already initialize this.props. If the only thing you are doing in your component's constructor is to initialize your props you can leave the constructor out completely. Otherwise you have to call the super constructor with the props:
constructor(props) {
// call the super constructor
super(props);
// do your additional initialization, e.g. set initial state
}
Also your example can't work properly as you did not initialize the local variable props inside your render() function. It has to look something like this:
render() {
const {children, ...props} = this.props;
return (
<View style={styles.wrap} {...props}>
<View style={styles.main}>
{children}
</View>
</View>
);
}
You must use the proper scope when referencing props. In other words, this is a class so props isn't defined in the render function, but this.props is. Add this. to the beginning and it will work. (e.g. {...this.props}
<View style={styles.wrap} {...this.props}>

Resources