Can child component only change parent state if event is triggered? - javascript

I'm trying to understand how a child component can change its parents' state and realize that the only examples in which I am able to successfully accomplish this (and the only examples I see online) deal with a callback being passed from a parent to a child that is then linked to an event (onClick, onChange etc..) in the child. Thus, can a child component only change it's parents' state if the child uses an event to call the inherited callback?
This works:
class Child extends React.Component{
handleClick(){
console.log('pressed')
this.props.message('Hi mom!')
}
render(){
return (<button onClick={this.handleClick.bind(this)}>Prese Me</button>)
}
};
class Parent extends React.Component {
constructor(props){
super(props)
this.state = {
messageFromChild: '',
}
this.callBackFromParent = this.callBackFromParent.bind(this);
}
callBackFromParent(dataFromChild){
this.setState({messageFromChild: dataFromChild})
}
render(){
return (
<div>
<h2>Message from Child is:</h2>
<h2>{this.state.messageFromChild}</h2>
<Child message={this.callBackFromParent}/>
</div>
)
}
}
But this leads to in infinite loop:
class Child extends React.Component{
render(){
this.props.message('Hi Mom')
return(
<h2>Dummy message from child</h2>
)
}
};
class Parent extends React.Component {
constructor(props){
super(props)
this.state = {
messageFromChild: '',
}
this.callBackFromParent = this.callBackFromParent.bind(this);
}
callBackFromParent(dataFromChild){
this.setState({messageFromChild: dataFromChild})
}
render(){
return (
<div>
<h2>Message from Child is:</h2>
<h2>{this.state.messageFromChild}</h2>
<Child message={this.callBackFromParent}/>
</div>
)
}
}

You don't necessarily need to use the functions as event handlers, but calling it directly on render would cause the parent component to setState immediately, which would result in another render of the Child component, and the loop continues. You could e.g. set a timeout in componentDidMount of the Child and it will work fine.

Related

Get the state of a class from anywhere like global variables

I have Parent class which has MainDiv and LoadngPopper.
In this case I want to get MainDiv state from LoadingPopper
class Parent extends React.Component{
render(){
return (
<MainDiv>
<LoadingPopper>
)
}
}
class MainDiv extends React.Component{
constructor(props) {
this.state = {
loading:0
}
}
}
class LoadingPopper extends React.Component{
render(){
//want to check MainDiv.state.loading here
return();
}
}
I can find how to give the parameter to parent to child or vice verse.
So, I can give the state from MainDiv -> Parent -> LoadingPopper
However in this case, I want to quickly access to MainDiv from anywhere like global variables.
Is it possible get the MainDiv instance directly from LoadingPopper?
Managing states inside a parent component allows accessing the states among its child components. (MainDiv and LoadingPopper)
Please check the official React documentation for more information:
https://reactjs.org/docs/lifting-state-up.html
Unless you have a huge and complicated component tree, I recommend simply sharing states from a parent component instead of using a state management library such as Redux to achieve this.
class Parent extends React.Component{
constructor(props) {
this.state = {
loading:0
}
this.toggleLoading = this.toggleLoading.bind(this);
}
toggleLoading() {
if(this.state === 0) {
this.setState({ loading: 1 });
return ;
}
this.setState({ loading: 0 });
}
render(){
return (
<MainDiv loading={this.state.loading} toggleLoading={this.toggleLoading} />
<LoadingPopper loading={this.state.loading} />
)
}
}
class MainDiv extends React.Component{
//set loading state here by using this.props.toggleLoading
}
}
class LoadingPopper extends React.Component{
//check loading state here
}

Is Component inside render function called child component

I have a little confused about children component. As I know children component is the component nested inside other component, for example
<Parent>
<Child />
</Parent>
But what is the component inside the render function of Parent component. What is it called? For example of Parent component
class Parent extends React.Component {
render() {
return (
<ComponentX>
{this.props.children}
</ComponentX>
)
}
}
Is ComponentX called a children of Parent Component?
I appreciate any explanation. Thanks in advance
Is ComponentX called a children of Parent Component?
NO.
ComponentX is called an Enclosing component of Parent's children.
Similar to how React.Fragments are used, without an enclosing element, there will be a warning:
Parse Error: Adjacent JSX elements must be wrapped in an enclosing tag
class Parent extends React.Component {
render() {
return (
<ComponentX>
{this.props.children}
</ComponentX>
)
}
}
this.props.children here is of Parent, and when you pass them into children of ComponentX. In ComponentX you will got this children.
Example:
class Parent extends React.Component {
render() {
return (
<ComponentX>
{this.props.children} // Here is children of Parent
</ComponentX>
)
}
}
In ComponentX:
class ComponentX extends React.Component {
render() {
return (
<div>
{this.props.children} // Here is children of ComponentX that you passed
// in above
</div>
)
}
}
In this case, you get children of Parent to use for childrent of
ComponentX

Reactjs : How to change props data from parent component that already distribute to child component?

I just creating a project and use a several component for a page and pass data by using props to each components. The problem is, when I have already change data from parent component to child component by using props and I have update the data from parent component, the child component still using the old data.
The example is just like this:
class Child extends Component{
constructor(props){
super(props);
this.state = {
variabel : props.variable
}
}
render() {
return (
<div>
<h1>{this.state.variable}</h1>
</div>
)
}
}
class Parent extends Component{
constructor(props){
super(props);
this.state = {
variabel : 'Hello'
}
}
render() {
return (
<div>
<Child variable={this.state.variable} />
</div>
)
}
}
So, when I run the page and update the variabel state in Parent Component, Child Component still show the old value. How to make it updated as the Parent Component data? Or I must using Redux for this case?
In general you'll only want to keep one particular piece of state in one place. If you reassign it in the constructor of Child, it will not update when the parent's state updates. So something like this pattern should work:
class Child extends Component{
// Note that no constructor is needed as you are not initializing any state or binding any methods.
render() {
return (
<div>
<h1>{this.props.variable}</h1>
</div>
)
}
}
class Parent extends Component{
constructor(props){
super(props);
this.state = {
variable : 'Hello'
}
}
render() {
return (
<div>
<Child variable={this.state.variable} />
</div>
)
}
}
A warning note about not initializing state with props is in the React docs for constructor, as a matter of fact.
Mitch Lillie's answer is the correct one. You should have only one source of truth.
In general, it's a good idea to keep the state in the nearest common ancestor of the components that depend on the state. Then you pass the props down.
If, however, you need to keep a copy of the prop in the child state, you should use the life cycles that React provides.
Codepen Live Demo
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {
variable: props.variable,
};
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (this.props.variable !== prevState.variable) {
this.setState({
variable: this.props.variable,
});
}
}
render() {
const varState = this.state.variable;
const varProps = this.props.variable;
return (
<div>
Child props: {varProps}
<br />
Child state: {varState}
</div>
);
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
setInterval(this.updateTime, 1000); // refresh every second
this.state = {
variable: new Date().toLocaleString(),
};
}
updateTime = () => {
this.setState({
variable: new Date().toLocaleString(),
});
}
render() {
const time = this.state.variable;
return (
<div>
<div>
Parent: {time}
</div>
<Child variable={time} />
</div>
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById('container')
);

Is there a way to control the child component function by parent component?

I tried to build a image upload tool, every child component have there own upload button.
Is there the way to let the upload function control by parent component?
following the code:
Child Component
class Child extends Component{
constructor(props){
super(props)
this.state={
imageUrl: 'base64'
}
}
componentDidMount(){
this.setState({imageUrl: this.props.image})
}
handleUpload(){
axios.post(this.state.imageUrl);
}
render(){
return(
<div>
<img src={this.state.imageUrl}/>
<button onClick={this.handleUpload.bind(this)}></button>
</div>
)
}
}
Parent Component
class Parent extends Component{
constructor(props){
super(props)
this.state={
imageFiles: [...image]
}
}
componentDidMount(){
}
render(){
return(
<div>
{
this.state.imageFiles.map(image=>{
return(
<Child image={image}/>
)
})
}
</div>
)
}
}
I know how to access the parent component function to child component by this way <child handle={this.handle.bind(this)}/> in the parent component.
Is there some method to let parent component functions can trigger all the child component?
You could move handle function in the parent component, then pass it to the child component like:
<Child image={image} onClickUpload={this.handleUpload}/>
Here is the same question
Make a ref for a child component and then call it within parent's function.

How do I change state within a child component by calling function in its parent?

I am attempting to change the state within a child component every time I call a function in it's parent component. How would I go about doing this? For Example,
class ParentComponent extends Component {
function onClick(){
// some function here to change child components state
}
render(){
return (
<div>
<ChildComponent />
<button onClick={this.onClick.bind(this)}>
</div>
)
}
class ChildComponent extends Component {
constructor(props){
super(props)
this.state = {
MyState: 1
}
}
render(){
return(
<div>
{this.state.MyState}
</div>
)
}
}
According to my understanding you are trying to achieve this:
class ParentComponent extends Component {
constructor(props){
super(props)
this.state = {
MyState: 1
}
}
function onClick(){
this.setState({MyState:this.state.MyState + 1})
}
render(){
return (
<div>
<ChildComponent sendToChild={this.state.MyState}/>
<button onClick={this.onClick.bind(this)}>
</div>
)
}
class ChildComponent extends Component {
render(){
return(
<div>
{this.props.MyState}
</div>
)
}
}
Call setState in your onClick handler -- this causes a rerender in the ParentComponent as well as any child component (unless a component returns false in shouldComponentUpdate, but you don't have this function implemented). However your child component will visually not change even when rerendered currently since it has no props.
Not sure what you want to achieve exactly, but if you were to move the state MyStatefrom ChildComponent to ParentComponent and pass MyState as a prop to ChildComponent, and in the onClick handler call setState and increment MyState then the ChildComponent would visually update.
Either put your onClick handler in the child component, lift the state up or pass the onClick through props.
What are you trying to accomplish?

Categories

Resources