Update parent React component from child component - reactjs

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() }}/>
...

Related

Display element based on event fired and props passed in

I am trying, to manipulate another element, by, passing props directly to it, and then have it display itself. If I pass true/false.
Live running code:
https://codesandbox.io/s/keen-dan-rt0kj
I don't know if it's possible to have a system of objects, and based on an event, tell a parent to display a child.
App.js
import React from "react";
import "./styles.css";
import Content from "./components/Content";
export default class App extends React.Component {
state = {
display: false
};
render() {
return (
<div className="App">
<button onClick={() => this.setState({ display: !this.state.display })}>
Display div
</button>
<Content display={this.state.display} />
</div>
);
}
}
./components/Content.js:
import React from "react";
export default class Content extends React.Component {
constructor(props) {
super();
this.state = {
display: props.display
};
}
render() {
const { display } = this.state;
return (
<div
id="mydiv"
className="mydiv"
style={{ display: display ? "block" : "none" }}
>
<h3>A simple div</h3>
</div>
);
}
}
Goal:
I want to based on a state, and based on fired event, display an element that already in store of root.
EDIT: I am aware that, this exists and can be used: import PropTypes from 'prop-types', however, I am not sure this is good practice, since it requires some parent or some other component to implement the props.
JUST Tried:
App:
<Content display={this.state.display} content={"Hello World"} />
Content:
<h3>{this.state.content}</h3>
It seems the passed in text, stored in Content state = {content: props.content} does get displayed, wheres, the boolean value does not work directly. Is there something wrong with sending in a bool ?
try this in your Content Component
export default class Content extends React.Component {
constructor(props) {
super();
this.state = {
};
}
render() {
return (
<>
{this.props.display?(
<div
id="mydiv"
className="mydiv"
>
<h3>A simple div</h3>
</div>
):null}
</>
);
}
}
The reason this may not be working is because you are initiating the state in a way that does not connect the display props after the component is initialized. This means that after the Content component is "constructed", the state of the Content and it's parent are not linked. This is because the constructor() function is only run once to initialize the state.
The best option you have is to not use the internal state of the Content component. Rather than initializing state with the display prop, just use the display prop in your render function.
Trying something like this might work
import React from "react";
export default class Content extends React.Component {
constructor(props) {
super(props);
}
render() {
const { display } = this.props;
return (
<div
id="mydiv"
className="mydiv"
style={{ display: display ? "block" : "none" }}
>
<h3>A simple div</h3>
</div>
);
}
}
Also I would reccommend using state in the root:
import React from "react";
import "./styles.css";
import Content from "./components/Content";
export default class App extends React.Component {
constructor(props) {
super();
state = {
display: false
};
}
render() {
return (
<div className="App">
<button onClick={() => this.setState({ display: !this.state.display })}>
Display div
</button>
<Content display={this.state.display} />
</div>
);
}
}

simplest approach of dynamically adding components in react

currently working on react. I have two components lets say ad and home . Inside home components i have one image and on click event of that image i want to render ad inside home component below image. Is there any simples method . thank you!
check this. i think this is what you want
//dynamically generate div
let DynamicDiv=()=>{
return (<div>
<p>i am here</p>
</div>)
}
class App extends Component {
constructor(props){
super(props)
this.state={
visible:false //visibility of Component
}
this.divVisiblity=this.divVisiblity.bind(this) //function is bind when user clicks on pic
}
divVisiblity(){
//this function will get called when user clicks on function
this.setState(()=>{return {visible:!this.state.visible}}) //changes visible state of Component when user clicks
}
render() {
return (
<div>
<div className="App">
{/* onClick is assigned function named divVisiblity */}
<img onClick={this.divVisiblity} src="https://placekitten.com/g/200/300" alt="test"/>
{/*this is ternary if else statement in js */}
{/* if visible = true ,display Component else dont */}
<div>
{this.state.visible && <DynamicDiv/>}
</div>
);
}
}
I think that will help to you.
export default class HomeComponent extends Component<Props> {
constructor(props) {
super(props);
this.state = {
renderAdComponent: false
};
this.onClickHandler = this.onClickHandler.bind(this);
}
onClickHandler() {
this.setState({renderAdComponent: !this.state.renderAdComponent})
}
render() {
return (
<View>
<Image onClick={this.onClickHandler}/>
{this.state.renderAdComponent ? <AdComponent/> : null}
</View>
);
}
}
What #sdkcy suggested is okay but the ternary operator isn't really needed. You can do the following
{ this.state.isAdShown && <ComponentToShow /> }
This gets rid of the useless : null result.

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}>

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

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.

Resources