React: How can I pass data between independent components - reactjs

I known how to pass data from a component to other but what I want to do is to have two independent component where one of them pass data to the other.
For example, <Component 1> pass data to <Component 2>. I don't want to pass data to <Component 2> inside the code of <Component 1>. What I want to know if its possible to pass data and how from <Component 1> to <Component 2>. Because, I want to have an independent component which makes its own tasks and at the end of these tasks, pass the data to other component which is not included in her own code.
This would be an example what I would like to do:
class Test extends Component{
constructor(){
super()
}
render(){
return(
<div>
<h1>Test</h1>
<Component 1 />
<Component 2 />
</div>
)
}
}
Therefore, is there any way to pass data between independent components in React.js?.

const { useState, createContext, useContext } = React;
const Context = React.createContext();
const MyComponent = () => {
const { name, updateName } = useContext(Context);
return (<span onClick={() => updateName('Jane')}>{name}</span>);
};
const App = () => {
const [name, updateName] = useState('John');
return (
<Context.Provider value={{ name, updateName }}>
<MyComponent />
<br/>
<MyComponent />
</Context.Provider>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
<div id="root" />
to exercise the snippet...
click on John to update name to Jane

You should be using state in the parent component that holds both the components and use some way of updating the parent state by the child component and consume it, in its basic way. Advanced way is to use Redux, but I don't think your current example needs it.
Let me show you a small example.
const Component1 = props => (
<div>
<h1>Component 1</h1>
<p>Please change the value here:</p>
<input
type="text"
onChange={e => props.changeState(e.target.value)}
value={props.value}
/>
</div>
);
const Component2 = props => (
<div>
<h1>Component 2</h1>
<p>Let me show the common value here:</p>
<pre>{props.value}</pre>
</div>
);
class App extends React.Component {
state = {
commonValue: "Hello"
};
changeState = val => {
this.setState({
commonValue: val
});
};
render() {
return (
<div className="App">
<Component1
value={this.state.commonValue}
changeState={this.changeState}
/>
<Component2 value={this.state.commonValue} />
</div>
);
}
}
This way, you will be able to change the values from two different components.
Working Snippet
const Component1 = props => (
<div>
<h1>Component 1</h1>
<p>Please change the value here:</p>
<input
type="text"
onChange={e => props.changeState(e.target.value)}
value={props.value}
/>
</div>
);
const Component2 = props => (
<div>
<h1>Component 2</h1>
<p>Let me show the common value here:</p>
<pre>{props.value}</pre>
</div>
);
class App extends React.Component {
state = {
commonValue: "Hello"
};
changeState = val => {
this.setState({
commonValue: val
});
};
render() {
return (
<div className="App">
<Component1
value={this.state.commonValue}
changeState={this.changeState}
/>
<Component2 value={this.state.commonValue} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<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>
Working Demo: https://codesandbox.io/s/priceless-sea-e7d99

If you need to have dependent data for independent components - you need to lift your state up to a common parent component.
For your particular example, the Test component might contain data needed to be shared between Component1 and Component2 as well as handlers for its changing.
You can read more about this in official documentation about Lifting State Up.

Related

React - Passing data counter from child to parents component

so, im just learning about props method and i want to try how to passing data from child to parent component.
im trying to make counter app, when click + the counter increasing and click - the counter decreasing
i have parent component like this
import React, { useState } from 'react';
import ComponentB from './ComponentB'
const ComponentA = () => {
const [counterB , setCounterB] = useState(0);
return(
<div>
<h1>ComponentB</h1>
<h3>{counterB}</h3>
<ComponentB
add={counterB => setCounterB(counterB)}
subtract={counterB => setCounterB(counterB)}/>
</div> );
}
export default ComponentA;
and child component like this
import React from 'react';
const ComponentB = (props) =>{
return(
<div>
<button onClick={()=> props.add(+1)}>+</button>
<button onClick={()=> props.subtract(-1)}>-</button>
</div>
);
}
export default ComponentB
With
return(
<div>
<h1>ComponentA</h1>
<h3>{counterB}</h3>
<ComponentB
add={diff => setCounterB(counterB + diff)}
subtract={diff => setCounterB(counterB + diff)}/>
</div> );
you pass the function diff => setCounterB(counterB + diff) to ComponentB as prop.add. This function sets the state of counterB to the first argument of that function. So when the button invokes props.add(+1)} the value of counterB is set to 1 every time it is pressed.
What you want is to add +1 to the state of counterB. Thus you should it this way:
// Get a hook function - only needed for this Stack Snippet
const {useState} = React;
const ComponentA = () => {
const [counterB , setCounterB] = useState(0);
return(
<div>
<h1>ComponentA</h1>
<h3>{counterB}</h3>
<ComponentB
add={diff => setCounterB(counterB + diff)}
subtract={diff => setCounterB(counterB + diff)}/>
</div> );
}
const ComponentB = (props) =>{
return(
<div>
<button onClick={()=> props.add(+1)}>+</button>
<button onClick={()=> props.subtract(-1)}>-</button>
</div>
);
}
ReactDOM.render(
<ComponentA/>,
document.getElementById("react")
);
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
I'd suggest to create a method in the Parent component to update the state given a value received from the child.
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
this.updateCountWithValue = this.updateCountWithValue.bind(this);
}
updateCountWithValue(value) {
let count = this.state.count;
count += value;
this.setState({
count: count
});
}
render() {
return (
<div>
<h1>{`Count: ${this.state.count}`}</h1>
<Child updateCount={this.updateCountWithValue} value={1} />
<Child updateCount={this.updateCountWithValue} value={-1} />
</div>
);
}
}
class Child extends Component {
render() {
return (
<div>
<button onClick={() => this.props.updateCount(this.props.value)}>
{this.props.value}
</button>
</div>
);
}
}
As you can see, the props of my Child component are:
The value that the child will update or change
A method to update the Parent component.
I made this sample so you can see how it works: https://codesandbox.io/s/child-to-parent-uvfmi?file=/src/App.js
Instead of this:
<ComponentB
add={counterB => setCounterB(counterB)}
subtract={counterB => setCounterB(counterB)}/>
Try this:
<ComponentB
add={val => setCounterB(counterB+val)}
subtract={val => setCounterB(counterB+val)}/> // using '+' coz val = -1

Patterns in React (wrapper)

Good day. I'm building a tree of components and want to use functions of root component in other components of tree. I throw function reference through all tree.
Also I use the object if me need get value from the function in not root componet.
Can you help me?
Can you show me how to do this as HOC ?
If it will be not so hard for you show examples on my code.
import React from 'react';
class Page extends React.Component{
Answer = {
value : ''
}
doSomething(){
console.log(this.Answer.value);
console.log('Ready!');
}
render(){
return(
<div>
<div>
<Body
ParentFunc={()=>this.doSomething()}
ParentParameters={this.Answer}
/>
</div>
</div>
)
}
}
export default Page
class Body extends React.Component{
render(){
const{
ParentFunc,
ParentParameters
} = this.props
return(
<div>
<div>
<SomeComponent
ParentFunc={()=>ParentFunc()}
ParentParameters={ParentParameters}
/>
</div>
</div>
)
}
}
class SomeComponent extends React.Component{
getAnswer(){
const{
ParentFunc,
ParentParameters
} = this.props
ParentParameters.value = 'Some text'
ParentFunc()
}
render(){
return(
<div onClick={()=>this.getAnswer()}>
We can?
</div>
)
}
}
I don't believe a Higher Order Component alone will solve your basic issue of prop drilling. A React Context would be a better fit for providing values and functions generally to "want to use functions of root component in other components of tree".
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
In a typical React application, data is passed top-down (parent to
child) via props, but such usage can be cumbersome for certain types
of props (e.g. locale preference, UI theme) that are required by many
components within an application. Context provides a way to share
values like these between components without having to explicitly pass
a prop through every level of the tree.
Start by creating your Context and Provider component:
const QnAContext = React.createContext({
answer: {
value: ""
},
doSomething: () => {}
});
const QnAProvider = ({ children }) => {
const answer = {
value: ""
};
const doSomething = () => {
console.log(answer.value);
console.log("Ready!");
};
return (
<QnAContext.Provider value={{ answer, doSomething }}>
{children}
</QnAContext.Provider>
);
};
Render QnAProvider in your app somewhere wrapping the React subtree you want to have access to the values being provided:
<QnAProvider>
<Page />
</QnAProvider>
Consuming the Context:
Class-based components consume contexts via the render props pattern.
<QnAContext.Consumer>
{({ answer, doSomething }) => (
<SomeComponent doSomething={doSomething} answer={answer}>
We can?
</SomeComponent>
)}
</QnAContext.Consumer>
Functional components can use the useContext React hook
const SomeComponent = ({ children }) => {
const { answer, doSomething } = useContext(QnAContext);
getAnswer = () => {
answer.value = "Some text";
doSomething();
};
return <div onClick={this.getAnswer}>{children}</div>;
};
Here is where using a Higher Order Component may become useful. You can abstract the QnAContext.Consumer render props pattern into a HOC:
const withQnAContext = (Component) => (props) => (
<QnAContext.Consumer>
{(value) => <Component {...props} {...value} />}
</QnAContext.Consumer>
);
Then you can decorate components you want to have the context values injected into.
const DecoratedSomeComponent = withQnAContext(SomeComponent);
...
<DecoratedSomeComponent>We can with HOC?</DecoratedSomeComponent>
Note: The point of doing all this was to move the values and functions that were previously defined in Page into the Context, so they are no longer passed from Page though Body to SomeComponent (or any other children components).
Demo
Sandbox Code:
const QnAContext = React.createContext({
answer: {
value: ""
},
doSomething: () => {}
});
const QnAProvider = ({ children }) => {
const answer = {
value: ""
};
const doSomething = () => {
console.log(answer.value);
console.log("Ready!");
};
return (
<QnAContext.Provider value={{ answer, doSomething }}>
{children}
</QnAContext.Provider>
);
};
const withQnAContext = (Component) => (props) => (
<QnAContext.Consumer>
{(value) => <Component {...props} {...value} />}
</QnAContext.Consumer>
);
class SomeComponent extends React.Component {
getAnswer = () => {
const { doSomething, answer } = this.props;
answer.value = "Some text";
doSomething();
};
render() {
return (
<button type="button" onClick={this.getAnswer}>
{this.props.children}
</button>
);
}
}
const DecoratedSomeComponent = withQnAContext(SomeComponent);
class Body extends React.Component {
render() {
return (
<div>
<div>
<QnAContext.Consumer>
{({ answer, doSomething }) => (
<SomeComponent doSomething={doSomething} answer={answer}>
We can?
</SomeComponent>
)}
</QnAContext.Consumer>
</div>
<div>
<DecoratedSomeComponent>We can with HOC?</DecoratedSomeComponent>
</div>
</div>
);
}
}
class Page extends React.Component {
render() {
return (
<div>
<div>
<Body />
</div>
</div>
);
}
}
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<QnAProvider>
<Page />
</QnAProvider>
</div>
);
}
Based on your current code I am making the assumption that Body does not modify the values of ParentFunc and ParentParameters before passing them down to SomeComponent.
You have a hierarchy
<Page>
<Body>
<SomeComponent>
</Body>
</Page>
and you want to pass props from Page to SomeComponent without going through Body.
You can do this using children
children is a special prop representing the JSX child elements of the component. We make it so that Body renders the children that it got through props:
class Body extends React.Component{
render() {
return(
<div>
<div>
{this.props.children}
</div>
</div>
)
}
}
We set that children prop by using a <SomeComponent/> element inside of the <Body>:
render() {
return (
<div>
<div>
<Body>
<SomeComponent
ParentFunc={() => this.doSomething()}
ParentParameters={this.Answer}
/>
</Body>
</div>
</div>
);
}
Note that you cannot directly modify the value that you got from the parent, which is what you were doing with ParentParameters.value = 'Some text'. If you want to update the state of the parent then you need to do that through your callback function props. So your code should look something like this:
import React from "react";
class Body extends React.Component {
render() {
return (
<div>
<div>{this.props.children}</div>
</div>
);
}
}
class SomeComponent extends React.Component {
state = {
showAnswer: false
};
onClick() {
// update answer in parent
this.props.setAnswer("Some text");
// change state to reveal answer
this.setState({ showAnswer: true });
}
render() {
return (
<div>
{this.state.showAnswer && <div>Answer is: {this.props.answer}</div>}
<div onClick={() => this.onClick()}>We can?</div>
</div>
);
}
}
class Page extends React.Component {
state = {
value: ""
};
render() {
return (
<div>
<div>
<Body>
<SomeComponent
answer={this.state.value}
setAnswer={(answer) => this.setState({ value: answer })}
/>
</Body>
</div>
</div>
);
}
}
export default Page;

Prevent rerender of sibling component which initiates a useState in wrapper component

I am not very experienced with React but I have a very simple Setup.
export default function App() {
const [title, setTitle] = useState("still-empty");
const myFunction = title => {
setTitle(title);
};
return (
<div className="App">
<ComponentA myFunction={myFunction} />
<br />
<br />
<ComponentB title={title} />
</div>
);
}
const ComponentA = ({ myFunction }) => {
console.log("Rendering Component A");
return (
<div onClick={() => myFunction(Math.random() * 1000)}> Component A </div>
);
};
export default ComponentA;
const ComponentB = ({ title }) => {
return <div> Title : {title}</div>;
};
export default ComponentB;
Here is a sandbox to test this: https://codesandbox.io/s/musing-cookies-g7szr
See that if you click on "ComponentA", that exact ComponentA gets rerendered (you can see it in console) although no props are changed on this component. This is a simplified example of my real use case. In my real use case, ComponentA is a map where a lot of stuff (zoom, center)
will be reset. I want to prevent these resets and also the 1 second it takes for rerendering. Therefor I present this simplified example.
So how do I pass an information from ComponentA to ComponentB, without rerendering ComponentA itself? Thanks for helping out here.
use useCallback in Parent so that the function is not created again and again but only on initial render.
use React.memo so that when no props are changed the component wont re-render.
App
export default function App() {
const [title, setTitle] = useState("still-empty");
const myFunction = useCallback(title => {
setTitle(title);
}, []);
return (
<div className="App">
<ComponentA myFunction={myFunction} />
<br />
<br />
<ComponentB title={title} />
</div>
);
}
ComponentA
import React, { memo } from "react";
const ComponentA = ({ myFunction }) => {
console.log("Rendering Component A");
return (
<div onClick={() => myFunction(Math.random() * 1000)}> Component A </div>
);
};
export default memo(ComponentA);
Working demo is here:
https://codesandbox.io/s/affectionate-boyd-v7g2t?file=/src/App.js

Can I pass ref with function component?

-I am using function component.
-for now I am using 3 components here, from that One is parent component and another 2 are child components.
-I need to access one child component methods or state to another child methods. I already done with class components with CreateRef but for now I need to use with function components but I am getting Null inside 'ref.current'.
export function SideBySideList(props) {
const ref = React.createRef();
//this is call inside ListPage after sucess
function updateRightList(id) {
ref.current.state.actualSearchedModel.Id = id
ref.current.fetchDataAndUpdate();
}
function itemClicked(id) {
updateRightList(id);
}
return (
<>
<div className="col-12 no-padding">
<div className={props.leftListLayoutClass}>
<ListPage
updateRightList={updateRightList}
/>
</div>
<div className={props.rightListLayoutClass}>
<ListPage
ref={ref}
/>
</div>
</div>
<>
);
}
According to the official documentation:
You may not use the ref attribute on function components because they
don’t have instances
So if your ListPage is functional component, you have to convert it to the class component. Or your ref must refer to the DOM element inside of ListPage.
function ListPage ({ref}) {
return <div ref={ref}>Hello!</div>
}
UPDATED:
function ParentComponent () {
const [state, setState] = React.useState(null);
const onChildMount = React.useCallback((dataFromChild) => {
setState(dataFromChild);
});
return (
<div>
<pre>{JSON.stringify(state, null, 2)}</pre>
<ChildComponent onMount={onChildMount} />
</div>
)
}
function ChildComponent (props) {
const thisShouldBePassedToTheParent = "from child with love";
React.useEffect(() => {
props.onMount(thisShouldBePassedToTheParent);
}, []);
return (
<div>child component</div>
)
}
ReactDOM.render(<ParentComponent />, document.querySelector("#root"));
<script src="https://unpkg.com/react#16.9.0/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16.9.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
With functional components you can use refs like this:
// Import our hooks
import React, { useRef, useEffect } from 'react';
// create our ref
const myInput = useRef();
// This is equivalent to our componentDidMount, this will focus
useEffect(() => myInput.current && myInput.current.focus());
// Parse our ref to our textField
<Textfield inputRef={myInput} />
Here you can read docs https://reactjs.org/docs/hooks-reference.html#useref
Also you may use refs like this directly:
<TextField inputRef={input => input && input.focus()} />
You can read full Article here: https://medium.com/javascript-in-plain-english/react-refs-both-class-and-functional-components-76b7bce487b8
If someone looking for solution where Parent is class component and Child is functional component, and want to get data from child (state, function)
Class component:
class Parent extends React.Component {
constructor(){
this.setReferenceToElement = element => {
this.fromChild = element;
}
}
handleClick(){
console.log(this.fromChild());
}
render(){
return (
<div>
<Child setRef={this.setReferenceToElement} />
<button onClick={handleClick}> Get state from child </button>
</div>
)
}
}
Functional component:
function Child(props){
// ... it has some state
props.setRef(state => state);
return <div> Test </div>
}

Automatically map the same props to multiple React components

I have multiple React components that will receive the same props...
...
render () {
const { someProps } = this.props
return (
<div className="someDiv">
<Component1 someProps={someProps}/>
<Component2 someProps={someProps}/>
</div>
)
}
...
The above code works fine but is there a more dynamic way of doing this? Mabye do a .map() over an array of Component names?
Array of components should work just fine.
const Component1 = (props) => <div>Component 1</div>
const Component2 = (props) => <div>Component 2</div>
const Component3 = (props) => <div>Component 3</div>
const components = [Component1, Component2, Component3]
class App extends React.Component {
render() {
const { someProps } = this.props
return (
<div>
<h3>Root component</h3>
{components.map((Component, index) =>
<Component key={index} someProps={someProps} />
)}
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Resources