If in Angular 2 is possible to connect two child components with each other how is it manageable in react js?
A) You can use Redux or Flux to keep a single state for the whole application, which you will be able to access from any component that you decide to connect with this state, called the Store.
You can read more about this in https://github.com/reduxjs/redux.
B) If both components are siblings, and the state you are trying to share is not something that you would care about in the rest of the application, you can pass the state from the parent to both children, as props, and also pass a function that allows the children to set the parent's state.
For example:
class Parent extends Component {
state = {
something: '',
}
changeSomething = (e) => {
this.setState({
something: e.target.value,
})
}
render() {
const { something, changeSomething } = this.state;
return(
<div>
<ChildrenA
something={something}
changeSomething={changeSomething}
>
<ChildrenB
something={something}
changeSomething={changeSomething}
>
</div>
);
}
Now both children have access to this.props.something and this.props.changeSomething and they can both change the parent's state and both will see the changes.
Hope it helps
Related
I have a redux-store with objects of initial values. And this store will get updated at a few places within the child component.
I created a stateless functional component as parent
const Parent = () => {
const store = useSelector(state => state);
const getInitState = () => {
depends on store, it will return an object as initial state for child component
}
let initState = getInitState(); //it has to be let instead of const, it could be changed during useEffect
useEffect(() => {
some initialization on mount
}, [])
return ( // return is simplified here
<Child initState={iniState} />
)
}
export default Parent;
I have a class child component something like below
class Child extends Component {
state = {
componentState: this.props.initState
}
....
}
export default Child;
I can't modify the child component It's a very complex component with many sub components which I dont handle.
Now I need to access setState function of child component from parent. Or I need to change the state of child from parent, is there a way to do that?
Yes, I understand a new design should be consider since it's anti-pattern, but I am just wondering if I can do it under current setting.
Thank you all in advance.
==============================================================
Edit: For whoever runs into the same problem, functional component does not support constructor. So I have included a breif correction to the answer.
Define parent as below
import React, { useRef } from "react";
const Parent = () => {
const childRef = useRef(null);
return (
<Child ref={childRef} />
)
}
export default Parent;
Then you are able to use childRef.current to access all function from child component.
The best way is using a react Context , and set state in parent then the child consume state of parent (using react hooks would be so easy than class component)
but in your case as you mentiened (I wonder I can do it under current setting)
you can use react refs :
first put ref prop in your rendered component tag then use it in parent to execute function that's declared inside child
as below :
inside parent component :
const Parent = () => {
.
.
.
constructor() {
//create react ref for our component
this.childComponent = React.createRef();
}
callChildFunction() {
// here using refs you can access function in you child refenrenced component
this.childComponent.cuurent.doSomeUpdateStateStuff(newState);
}
return ( // return is simplified here
<Child ref={this.childComponen} initState={iniState} />
)
...
}
and your child :
class Child extends Component {
state = {
componentState: this.props.initState
}
doSomeUpdateStateStuff(state) {
// stuff updating state callled from parent
}
....
}
how to update a component after updating props?
I have the following component structure:
MyList.js
render() {
return(
<ComponentList products={props.products}>
<ComponentBoard product={props.product[i]} //send choosen product(1) from list(100 products)
)
}
and next components have 2 similar component contentRow
ComponentList.js (
same(
<contentRow > list .map() //100 contentRow
)
ComponentBoard.js
same(
<contentRow > // 1 contentRow
)
in the component componentRow there are fields that display and through redux change the data in the store, for example, the username.
And when I open the ComponentBoard component and change the value in the ComponentRov field, the value in the ComponentList> componentRow should also change.
For a better understanding:
ComponentList is a table of ComponentsRow, when clicked to row, That opens the ComponentBoard window, in which there is also a componentRow.
Question: how to update the data that is displayed in componentList from componentBoard? they have similar props from 1 store
When serializing props as initial state you should listen for changes in props and update the state accordingly. In class based components you use componentDidUpdate in functional components you can achieve the same result with an useEffect listening for changes in a given prop
const Component = ({ foo }) =>{
const [state, setState] = useState(foo) //initial state
useEffect(() =>{
setState(foo) //everytime foo changes update the state
},[foo])
}
The class equivalent
class Component extends React.Component{
state = { foo : this.props.foo } // initial state
componentDidUpdate(prevProps){
if(prevProps.foo !== this.props.foo)
this.setState({ foo : this.props.foo }) //everytime foo changes update the state
}
}
for a better understanding of React, I recommend you read
React Life Cycle
the general idea is to make your list into the state of the MyList.js , that way, u can update it through a function in Mylist.js and pass it as a prop to the ComponentBoard . Now you can change the state of MyList and when that changes, so does ComponentList.
class MyList extends Component {
constructor(){
super();
this.state = {
// an array of objects
}}
handleBoardChange = () => { some function using this.setState }
// the rest of your Mylist class
}
Lets say I have a component defined like this -
// actioncomponent.js
import React from 'react';
class ActionComponent extends React.Component {
state = {
isAction: false;
}
doAction = () => {
this.setState({isAction: true})
}
render () {
return (
<div>
Some render stuff..
</div>
)
}
}
export default ActionComponent
From another completely different file I want to set the state for the first component without rendering it in the new file so I need not use refs or props.
// newfile.js
import ActionComponent from './actioncomponent.js'
ActionComponent.doAction()
I'm aware the doAction can't be exported and calling it static doesn't have access to state either. How do I achieve something like this?
In React ecosystem you probably don't need this.
You can pass this method to a child component:
class ActionComponent extends React.Component {
state = {
isAction: false
}
doAction = () => {
this.setState({isAction: true})
}
render () {
return (
<div>
<Child doAction={this.doAction} />
</div>
)
}
}
And then in a Child component you can fire this action
// ...
render() {
<button onClick={() => props.doAction()}>Test</button>
}
If you need to fire action on parent, instead of child you might want to structure your state on upper level, or lift state up.
You can also achieve similar goal without drilling props, but you'll need some state management tool, e.g. Redux or in some cases Context API would be a great fit.
I'd like to know, how to handle the PropTypes Error when passing a component as a child:
Failed prop type: The prop `value` is marked as required in `ChildComponent`, but its value is `undefined`.
The render works as expected and it's passing the value prop correctly.
I suppose this happens because I am putting the component in the App component's render function without any props.
I am only passing those props to the ChildComponent when the ParentComponent maps over its children (which is the ChildComponent).
See the code: https://codesandbox.io/embed/r70r5z3j9q
Is there a way to prevent this from happening?
How should I be structuring my components?
Am I not supposed to passed components as children?
EDITED: Changed prop "name" to "value". To give it a more generic feel.
I tried to simplify the problem in the code.
I know I could pass the prop directly in App.
The use case would be when the parent is doing calculations and those calculations are supposed to be passed to the child. Without explicitly knowing what these children are.
That's why I'm using it as child in the first place.
You're using cloneElement and you're passing prop to it, not to original element. To fix it, pass props directly:
const App = () => (
<div>
<ParentComponent>
<ChildComponent name="bob" />
</ParentComponent>
</div>
);
You could easily pass component as a prop (not children) to you ParentComponent and render it only after it takes some heavy calculations:
const App = () => (
<div>
<ParentComponent component={ChildrenComponent} />
</div>
);
const ParentComponent extends React.Component {
state = { heavyComputationFinished: false } // initial state
componentDidMount() {
runYourHeavyComputations
.then(() => { this.setState({ heavyComputationsFinished: true }) })
}
render() {
const { component } = this.props
const { heavyComputationsFinished, name } = this.state
// return nothing if heavy computations hasn't been finished
if (!heavyComputationsFinished) { return null }
// we're getting this component (not its rendering call) as a prop
return React.render(component, { name })
}
}
I have a form that has a submit button.
That form calls a function onclick that sets the state of something from false to true.
I then want to pass this state back to the parent so that if it is true it renders componentA but if it is false it renders componentB.
How would I do that in react?
I know I need to use state or props but not sure how to do it. also is this contradicting the one-way flow react principle??
ComponentA code:
<form onSubmit={this.handleClick}>
handleClick(event) {
this.setState({ decisionPage: true });
event.preventDefault();
};
Parent component that controls what it displays:
return (
<div>
{this.props.decisionPage ?
<div>
<LoginPage />
</div>
:
<div>
<Decision showThanks={this.props.showThanks}/>
</div>
}
</div>
)
Move handleClick to the parent and pass it to the child component as a prop.
<LoginPage handleClick={this.handleClick.bind(this)}/>
Now in the child component:
<form onSubmit={this.props.handleClick}>
This way submitting the form will update the state in parent component directly. This assumes you don't need to access updated state value in child component. If you do, then you can pass the state value back from the parent to the child as a prop. One-way data flow is maintained.
<LoginPage handleClick={this.handleClick.bind(this)} decisionPage={this.state.decisionPage}/>
Pass State as a Prop
I have recently learned a method that works great for changing state in a <Parent /> component from a <Child /> component.
This might not be the exact answer for this question, but it is surely applicable to this situation and other similar situations.
It works like this:
set the default STATE in the <Parent /> component - Then add the 'setState' attribute to the <Child />
const Parent = () => {
const [value, setValue] = useState(" Default Value ");
return (
<Child setValue={setValue} />
)
}
Then change the state(in Parent) from the Child component
const Child = props => {
return (
<button onClick={() => props.setValue(" My NEW Value ")}>
Click to change the state
</button>
)
}
When you click the button, the state in the <Parent /> component will change to whatever you set the state to in the <Child /> component, making use of "props".. This can be anything you want.
I Hope this helps you and other devs in the future.
In Parent Component:
getDatafromChild(val){
console.log(val);
}
render(){
return(<Child sendData={this.getDatafromChild}/>);
}
In Child Component:
callBackMethod(){
this.props.sendData(value);
}
Simple Steps:
Create a component called Parent.
In Parent Component create a method that accepts some data and sets
the accepted data as the parent's state.
Create a component called Child.
Pass the method created in Parent to child as props.
Accept the props in parent using this.props followed by method
name and pass child's state to it as argument.
The method will replace the parent's state with the child's state.
Here is an example of how we can pass data from child to parent (I had the same issue and use come out with this )
On parent, I have a function (which I will call from a child with some data for it)
handleEdit(event, id){ //Fuction
event.preventDefault();
this.setState({ displayModal: true , responseMessage:'', resId:id, mode:'edit'});
}
dishData = <DishListHtml list={products} onDelete={this.handleDelete} onEdit={(event, id) => this.handleEdit(event, id)}/>;
At the child component :
<div to="#editItemDetails" data-toggle="modal" onClick={(event)=>this.props.onEdit(event, listElement.id) }
className="btn btn-success">
In React you can pass data from parent to child using props. But you need a different mechanism to pass data from child to parent.
Another method to do this is to create a callback method. You pass the callback method to the child when it's created.
class Parent extends React.Component {
myCallback = (dataFromChild) => {
//use dataFromChild
},
render() {
return (
<div>
<ComponentA callbackFromParent={this.myCallback}/>
</div>
);
}
}
You pass the decisionPage value from the child to the parent via the callback method the parent passed.
class ComponentA extends React.Component{
someFn = () => {
this.props.callbackFromParent(decisionPage);
},
render() {
[...]
}
};
SomeFn could be your handleClick method.
if your parent component is a functional component you can now use the use context way. Which involves passing the ref to the object and the ref to the stateChanging method. What this will allow you to do is change state from parrent in child and also ref tht state while remaining synced with Parent State. You can learn more about this in a youtubeVideo by codedamn titled 'React 16.12 Tutorial 20: Intro to Context API' and 'React 16.12 Tutorial 21: useContext'
This works exactly what I wanted. But in case of set of data with say 50 records with (customer_id, customer_name) as values to be updated from child to parent, then this lags. Do the setState using React.useEffect in child component
i have same problem and so performed this code :
in Parent
const PARENT = () => {
const [value, setValue] = useState("....");
return (
)
}
in Child
const CHILD = props => {
return (
<button onClick={() => props.setValue("....")}>
Click to change the state
</button>
)
}