16
 class App extends Component {
  constructor() {
    super();
    this.state = {
      name: 'React'
    };
    this.setState=this.setState.bind(this)
  }

  render() {
    return (
      <div>
        <Hello name={this.state.name} />
        <p>
          Start editing to see some magic happen :)
        </p>
        <Child {...this}/>
      </div>
    );
  }
}

child Component
var Child=(self)=>{
  return(
    <button  onClick={()=>{
      self .setState({
        name:"viswa"
      })
    }}>Click </button>
  )

here I am binding the setState function and send this as props to child component.This will change state of parent from child.Is this proper way?

viswa ram
  • 461
  • 2
  • 4
  • 9
  • better pass a parent's function that does the state change. – yBrodsky May 07 '18 at 13:29
  • But this is simple than passing function.If I want change many state change. this will be simple and faster way compare to passing function right ?@yBrodsky – viswa ram May 07 '18 at 13:31
  • I have only theoretical experience with react. But I never saw this. All the time they pass on functions. – yBrodsky May 07 '18 at 13:33
  • @yBrodskyYeah.I just try this. It's also working. I want to there won't be any error. If i did like this anyway thank you – viswa ram May 07 '18 at 13:36
  • I strongly discourage this approach. While it will work, it's quite anti-pattern to do so. The only thing you are likely to need from `this` is the `state` anyway. So rather than passing down the **whole instance**, just send down a function that gives you full control over the state. – Chris May 07 '18 at 13:42
  • @Chris how is this an anti-pattern? The `setState` is already a function – Ricky Boyce Dec 20 '20 at 20:56
  • @RickyBoyce it's anti-pattern for a number of reasons. A child component should never need to know the internals of its child component. For example, if the state name were to change from `name` to, let's say, `title` then you would also have to update the child onClick callback. The correct way of doing this is passing down a function that just takes the updated name as a parameter. Passing down the entire instance is simply something you should never do in React. Never ever. – Chris Dec 21 '20 at 03:04

4 Answers4

10

You shouldn't pass the setState directly, as the setState function will not change the state immediately.

as the documents said:

Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.

setState() does not always immediately update the component. It may batch or defer the update until later. So you'd better to manage the calling of setState function together as there may have competing of mutating parent's state. It is not recommended to pass this function to another component.

Encapsulating the calling of setState function in one class makes your code stronger.

欧阳维杰
  • 1,608
  • 1
  • 14
  • 22
9

But this is simple than passing function.If I want change many state change. this will be simple and faster way compare to passing function right ?

The correct way to do this is as simple as yours and does not violate best practices:

class App extends Component {
  state = {
      name: 'React',
  };

  render() {
    return (
      <div>
        <Hello name={this.state.name} />
        <p>
          Start editing to see some magic happen :)
        </p>
        <Child onClick={() => this.setState({name: 'viswa'})}/>
      </div>
    );
  }
}

const Child=({onClick})=>(
    <button onClick={onClick}>Click</button>
);
trixn
  • 15,761
  • 2
  • 38
  • 55
  • 1
    you are sending function as props to child .I am also sending setState function as props.So both are same right? – viswa ram May 07 '18 at 13:40
  • 2
    @viswaram By passing `setState` to the child you are exposing an internal of the parent. You child has to know how the state is implemented and you can't reuse the child component because of that. It's just not a good practice and has no advantages to the correct way to do it. – trixn May 07 '18 at 13:45
0

As @yBrodsky said, you should rather pass down a function which does mutate the state. Here is an example:

class App extends Component {
  constructor() {
    super();
    this.state = {
      name: 'React'
    };
    this.update=this.update.bind(this);
  }

  update(nextState) {
    this.setState(nextState);
  }

  render() {
    return (
      <Child updateParent={this.update} />
    );
  }
}

const Child = ({updateParent}) => (
  <button onClick={() => updateParent({name: 'Foo bar'})}>Click</button>
);

You now have full control over the state of the Parent in the child. Just pass the object to be shallowly merged into the parent state. In this example, name in App will change to Foo bar on button click.

Chris
  • 57,622
  • 19
  • 111
  • 137
  • thank you.I can do like this.But If i send this as a props.I can have full control over all state,all props of the parent component .I can access any state and any props. this is similar like passing props . I don't why this is not correct way? – viswa ram May 07 '18 at 13:45
  • 1
    It's wrong in many ways. It is important to remember that `this` is more than just the `state`, `props` and any component functions you may have. It's the whole instance. Not only is it unnecessary, but it can also interfere with how your Child component re-renders. If you turn `this` of the parent into a prop of the child, any internal "behind-the-scenes" changes may cause the component to re-render. It may work, and it might be flexible in your eyes, but if you want to implement "proper programming practices", you should avoid your method at all costs. – Chris May 07 '18 at 13:52
  • 1
    Thank you.@Chris.I will avoid to this hereafter – viswa ram May 07 '18 at 13:54
  • 1
    This definitely works but it couples the child component to the parent implementation and can be considered a bad practice. It is almost always better to explicitly define an interface of callbacks for all events the parent is interested in. – trixn May 07 '18 at 13:55
  • @trixn, OP stated that they wanted a flexible solution if they needed several state changes. I agree that it is better to define dedicated function per state change, but I will also disagree that this is bad practice (if the former approach isn't viable). The only difference here is that you are passing key-values (through an object) rather than just the value alone from the Child which is then coupled with a key in the Parent. Both approaches will still generate key-value pairs to be shallowly merged into the state. – Chris May 07 '18 at 13:59
  • @Chris A child should not need to know about the implementation of the parent. With this solution there is no clear interface and the child needs to know exactly how the parent implementation looks like to make state changes that make sense. There is just no benefit to the correct way to do it (defining an interface) as you still need to implement in the child what should have been implemented in the parent. – trixn May 07 '18 at 14:06
  • @trixn I also said that it's preferable to pass down functions in the fashion that you did in your answer. However it does not answer the question of how to expose `setState` in the Child and achieve the flexibility that OP wants. It's good that you pointed this out, but again, this it doesn't answer the question at hand. The benefit, despite the design flaws, is that an interface could get enormous if the Parent state is big and the Child (for some reason) needs access to all of those. We can sit here and speculate all day, but this is my solution to a "safe" exposure of setState to the child – Chris May 07 '18 at 14:14
0

i guess in functional components its possible to send your setState to childrens and change parent state in them but not in class base components

H.hashemi
  • 49
  • 5
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 08 '22 at 17:59