I have an application in reactjs. I want to get data from the input, from Component.js, into Component2.js. The function that get data from input is stored in sources.js.
export const getData = e => {
const value = e.target.value;
console.log(value);
return value;
};
Unfortunately when i want to get data in Component2, i don't get anything.
Question: How keeping this structure of folders to get data from Component1 in Component2?
Demo https://codesandbox.io/s/vigorous-vaughan-62mqe?file=/src/Component2.js
You can use React Context API to achieve this solution.
you can lifted up your state from child to parent and then pass that data from parent to another child (sibling). Here is the example:
Parent Component
import React, {useEffect, useState} from 'react';
import Child from "./Child";
import Sibling from "./Sibling";
function CParent(props) {
const [value, setValue] = useState(false);
function setOpeningValue(value) {
console.log('From Child to Parent:' + value);
setValue(value);
}
return (
<div>
<Child setOpeningValue={setOpeningValue}/>
<Sibling value={value}/>
</div>
);
}
export default CParent;
Child Component
import React, {useEffect, useState} from 'react';
// Child to Parent communication
function Child(props) {
const {setOpeningValue} = props;
const [value, setValue] = useState('');
function clickHandler() {
setOpeningValue(`changes is ${value}`);
}
function changeHandler(event) {
setValue(event.target.value);
}
return (
<div>
<input onChange={changeHandler} />
<button onClick={clickHandler}>pass data to parent</button>
</div>
);
}
export default Child;
Sibling Component
import React, {useEffect, useState} from 'react';
function Sibling(props) {
const {value} = props;
return (
<div>
This value is showing from Child to Parent to Another Child (Sibling): {value}
</div>
);
}
export default Sibling;
Related
I was having a parent component named Cart.jsx in react and the child component named Card.jsx.
The Parent component looks like this.
Cart.jsx
import React, { useState, useEffect, useContext } from "react";
import Card from "../../Components/Card";
function Cart() {
const cart = [**Array of Objects**]
const [total,setTotal] = useState([]);
return (
<div className="cart__Items">
<Card item={cart[0]} />;
<Card item={cart[1]} />;
<Card item={cart[2]} />;
</div>
)
}
export default Cart;
And the Card Component looks as follows
Card.jsx
import React, { useState } from "react";
function Card() {
const [price,setPrice] = useState(0);
// in-between implemented some function to calculate price value.
return (
<div>
// rendering code
</div>
)
}
export default Card;
Now the problem is, how do I get the price data of each child component and store them in the total array of the parent component.
Here the parent has 3 Cardcomponents, I need to get the price data from each component and store them in the Cart component
Here is the code. I hope this might help
import React, { useState, useEffect, useContext } from "react";
import Card from "../../Components/Card";
function Cart() {
const cart = [**Array of Objects**]
const [total,setTotal] = useState(0);
return (
<div className="cart__Items">
{cart.map(crt =><Card item={crt} total={total} setTotal={setTotal} />}
</div>
)
}
export default Cart;
import React, { useState } from "react";
function Card(props) {
const [price,setPrice] = useState(0);
const {setTotal, total} = props
useEffect(()=>{
setTotal(total+price)
},[])
// in-between implemented some function to calculate price value.
return (
<div>
// rendering code
</div>
)
}
export default Card;
import React, { useState, useEffect, useContext } from "react";
import Card from "../../Components/Card";
function Cart() {
const cart = [**Array of Objects**]
const [total,setTotal] = useState([]);
return (
<div className="cart__Items">
{cart.map((item) => (<Card item={item} setTotal={setTotal} />))}
</div>
)
}
export default Cart;```
Now you have access to the setTotal function inside each card Item from which you can update the parent state of "total".
If you feel like the individual prices are to be calculated by the child you should use an event handler prop :
Cart.jsx
import React, { useState, useEffect, useContext } from "react";
import Card from "../../Components/Card";
function Cart() {
const cart = [**Array of Objects**]
const [total,setTotal] = useState(0);
const handlePriceCalculated = price => {
setTotal(total + price);
}
return (
<div className="cart__Items">
<Card item={cart[0]} onPriceCalculated={handlePriceCalculated} />
<Card item={cart[1]} onPriceCalculated={handlePriceCalculated} />
<Card item={cart[2]} onPriceCalculated={handlePriceCalculated} />
</div>
)
}
export default Cart;
Card.jsx
import React, { useState } from "react";
function Card({
onPriceCalculated
}) {
const [price,setPrice] = useState(0);
// in-between implemented some function to calculate price value.
...
setPrice(calculatedValue)
onPriceCalculated(calculatedValue)
...
return (
<div>
// rendering code
</div>
)
}
export default Card;
Giving the responsability to the child to set the total is a bad practise and will result in your components not to be reusable as they would be too hardly coupled.
In my app, I want to pass the global store of my application to the child components via context. For the sake of an example, I have created 2 child components namely Child1 and Child2, and passing increment and decrement counter functions along with the corresponding counter values to them. Child1 is responsible for incrementing counter1 and child2 for decrementing counter2. When I am invoking the increment/decrement function in the components, the other component is uselessly getting re-rendered along with the parent. How can I prevent this from happening?
Please find the above use-case here
Below is the code for the same,
App.js
import React, { useState, useCallback } from 'react';
import './style.css';
import { UserContext } from './Context.js';
import Child1 from './Child1';
import Child2 from './Child2';
export default function App() {
const [counter1, setCounter1] = useState(0);
const [counter2, setCounter2] = useState(0);
const IncrementCounter = useCallback(
() => setCounter1((prevState) => prevState + 1),
[setCounter1]
);
const DecrementCounter = useCallback(
() => setCounter2((prevState) => prevState - 1),
[setCounter2]
);
const store = {
child1: {
counter1,
IncrementCounter,
},
child2: {
counter2,
DecrementCounter,
},
};
console.log('App re-rendering');
return (
<UserContext.Provider value={store}>
<Child1 />
<Child2 />
</UserContext.Provider>
);
}
Child1.js
import React, { useContext } from 'react';
import { UserContext } from './Context.js';
const Child1 = () => {
const store = useContext(UserContext);
const { child1 } = store;
console.log('Child1 Re-rendering');
return (
<div>
<p>{`Counter1 value : ${child1.counter1}`}</p>
<button onClick={child1.IncrementCounter}>Increment</button>
</div>
);
};
export default React.memo(Child1);
Child2.js
import React, { useContext } from 'react';
import { UserContext } from './Context.js';
const Child2 = () => {
const store = useContext(UserContext);
const { child2 } = store;
console.log('Child2 Re-rendering');
return (
<div>
<p>{`Counter2 value : ${child2.counter2}`}</p>
<button onClick={child2.DecrementCounter}>Decrement</button>
</div>
);
};
export default React.memo(Child2);
Context.js
import React from 'react';
const UserContext = React.createContext();
export { UserContext };
I am using useRef hook in my context. I am logging that out in useEffect hook inside context. I passing that useRef variable so that it can be accessed my components. Here is the context.
import { createContext, useContext, useRef, useEffect } from "react";
export const SearchContext = createContext({});
export const useSearch = () => useContext(SearchContext);
const SearchProvider = ({ children }) => {
const loader = useRef(null);
useEffect(() => {
console.log(loader); // returns {current: null}
}, []);
return (
<SearchContext.Provider
value={{
loader
}}
>
{children}
</SearchContext.Provider>
);
};
export default SearchProvider;
Next in my component I am adding ref property to div element with value loader which is coming from context. However, when I run this code I see {current: null} for loader. How can I use useRef in context to have access to DOM elements in component to make this work?
Here is my component
import { useSearch } from "./context";
const Component = () => {
const { loader } = useSearch();
return (
<div>
<div ref={loader}>Hello</div>
</div>
);
};
export default Component;
Here is the sandbox link.
https://codesandbox.io/s/nervous-jepsen-l83mf?file=/src/component.js:0-203
I am trying to make a HOC that handles some functionalities in react and i am creating my HOC this wat
import React, { useState } from "react";
export default function withFormControl(WrappedComponent) {
return props => {
const onChangeField = e =>
setFields({ ...fields, [e.target.id]: e.target.value });
const [fields, setFields] = useState({});
const submitForm = e => {
console.log(fields);
e.preventDefault();
};
return (
<WrappedComponent
onChangeField={onChangeField}
submitForm={submitForm}
fields={fields}
{...props}
/>
);
};
}
And i am using it in my component like this:
import React, { useState } from "react";
import { Col, Form, FormGroup, Label, Input, Button } from "reactstrap";
import { Typo, Ico, AuthLayout } from "../../../components";
import "./Applicant.css";
import FormInput from "../../../components/common/FormInput/FormInput";
import withFormControl from "../../../hocs/WithFormControl";
function Applicant(props) {
console.log(props); // I get the props here
const subFunction = props => {
console.log(props); // returns undefined
}
}
export default withFormControl(Applicant);
I cant get the props in the inner function, any reason for this behavior?
Problem is that param of function called subFunction is shadowing variable from outer scope and then subFunction is called without any params.
Edit: Perhaps this could be referenced as a context subscriber?
I'm not even sure if this is the right concept that I'm trying to achieve. I want to be able to create a component that does the dirty work and just attaches context to the component that can the be consumed..
I've tried to find anything similar with no luck, which, leads me to believe I am not thinking of the right literal context of what it is I'm doing...
I've tried something like this:
import React, { Component } from "react";
export const Context = React.createContext();
export class ContextProvider extends Component {
state = {
scanning: false
};
render() {
return (
<Context.Provider
value={{
state: this.state,
handleClick: () => this.setState({
scanning: !this.state.scanning
})
}}
>
{this.props.children}
</Context.Provider>
);
}
}
And I trying to make it work with this..
import React from "react";
import { Context } from "./Context";
const WithContext = (children) => (props) => {
return (
<Context.Consumer>
{ state => (<children {...props} context={state} />) }
</Context.Consumer>
)
};
and then consuming with...
...
<WithContext>
<MyComponent />
</WithContext>
...
But, it just seems to fail or states that I'm returning a function instead of a react component..
Your WithContext component will not work like that... It needs to be a function that has the same functionality as the render function. like so:
import React from "react";
import { Context } from "./Context";
const WithContext = ({ children, ...props }) => (
<Context.Consumer>{state => React.Children.map(children, (child) => (
React.cloneElement(child, { context: state })
))}</Context.Consumer>
);
note that we traverse every direct child of the withContext children using React.Children.map (docs) and add a context prop to them by making use of React.cloneElement (docs). This keeps the child component's original props and shallow merges them into the second parameter passed to the function.
There are a bunch of little errors in your code for using context... Here is a complete example...
Let's say we have a structure where we have App.js -> Parent.js -> Child.js components... Instead of passing the data via props from App to Parent to Child we want to make use of the context API and avoid the prop drilling and have the Child consume the data directly...
Here is what that will look like:
context.js:
import React from 'react';
const Context = React.createContext();
export class Provider extends React.Component {
state = { name: 'Bob', age: 20 };
handleGrowUp = () => {
this.setState({ age: this.state.age + 1 });
};
render() {
return (
<Context.Provider
value={{
state: {
...this.state,
},
actions: {
growUp: this.handleGrowUp,
},
}}
>
{this.props.children}
</Context.Provider>
);
}
}
export const Consumer = Context.Consumer;
App.js:
import React from 'react';
import Parent from './Parent';
import { Provider } from './context';
const App = () => (
<Provider>
<Parent />
</Provider>
);
export default App;
Parent.js:
import React from 'react';
import Child from './Child';
const Parent = () => (
<div>
<Child />
</div>
);
export default Parent;
Child.js:
import React from 'react';
import { Consumer } from './context';
const Child = () => (
<div>
<Consumer>
{value => (
<div>
<p>{value.state.name}</p>
<p>{value.state.age}</p>
<button onClick={value.actions.growUp}>Grow Up</button>
</div>
)}
</Consumer>
</div>
);
export default Child;
Here is a working demo: https://codesandbox.io/s/9z06xzlyly