-1

In my code this.setState doesn't seem to be updating this.states but re-render is triggered. componentWillUpdate callback is also showing the correct parameters.

class TimeButton extends React.Component {
  constructor(){
    super();
    this.states = {
      percentage : 50
    }
  }
  componentWillUpdate(nextProps, nextState){
    console.log("componentWillUpdate currentstate")
    console.log(this.states);
    console.log("componentWillUpdate nextstate")
    console.log(nextState);

  }

  componentDidMount(){
    let component = this;
    console.log("componentDidMount");
    console.log(this.states);

    this.setState({
      percentage : 70,
      test : 10101010
    }, () => {
      console.log("callback setState");
      console.log(this.states);
    })

  }

  componentWillUnmount(){
  }

  handleClick(){
    this.props.onClick(component.props);
  }

  render(){
    console.log("render");
    console.log(this.states);
    let component = this;
    let { buttonInnerRadius, buttonOuterRadius, x, y } = this.props
    return (
      <Group onClick={component.handleClick.bind(component)}>
        <CircularBar x={x} y={y} innerRadius={buttonInnerRadius} outerRadius={buttonOuterRadius} ref="bar" percentage={this.states.percentage}></CircularBar>
        <Circle x={x} y={y} radius={buttonOuterRadius}></Circle>
      </Group>
    )
  }
}

So here is the result

my program's output

Am I doing something wrong here ? setState have worked before somewhere else I coded

If I do stupid things like

this.states.percentage = 70
this.states.test = 101010
this.forceUpdate()

It works just fine but that looks like a bad idea

so far I have checked out

Why is my setState is not working? [duplicate]

Why is 'this.setState' not working?

Aishwarya
  • 987
  • 3
  • 10
  • 26
Rmxhaha
  • 87
  • 7

2 Answers2

1

It is just a typo in your code. A component's state is called state, not states.

Tholle
  • 108,070
  • 19
  • 198
  • 189
1

@Tholle is precise, this.state exists inside React class module. There is nothing like this.states.

/**
 * Module for creating composite components.
 *
 * @class ReactClass
 */
var ReactClass = {

  createClass: function(spec) {
    // To keep our warnings more understandable, we'll use a little hack here to
    // ensure that Constructor.name !== 'Constructor'. This makes sure we don't
    // unnecessarily identify a class without displayName as 'Constructor'.
    var Constructor = identity(function(props, context, updater) {
      // This constructor gets overridden by mocks. The argument is used
      // by mocks to assert on what gets mounted.

      if (__DEV__) {
        warning(
          this instanceof Constructor,
          'Something is calling a React component directly. Use a factory or ' +
          'JSX instead. See: https://facebook.github.io/react/warnings/legacy-factories.html'
        );
      }

      // Wire up auto-binding
      if (this.__reactAutoBindPairs.length) {
        bindAutoBindMethods(this);
      }

      this.props = props;
      this.context = context;
      this.refs = emptyObject;
      this.updater = updater || ReactNoopUpdateQueue;

      this.state = null;

You can put inside the this.state anything you need via the setState method. Here I am setting the state a with the value 'a'.

 this.setState({ a: 'a' });

If I do stupid things like

this.states.percentage = 70
this.states.test = 101010
this.forceUpdate()

This would be dynamically adding states property. However, this is not smart.

The states should always be set using the setState method and never directly even if you improve the typo. This should be done asynchronously like explained in here.

File: react/docs/js/react.js
1220: /**
1221:  * Sets a subset of the state. Always use this to mutate
1222:  * state. You should treat `this.state` as immutable.
1223:  *
1224:  * There is no guarantee that `this.state` will be immediately updated, so
1225:  * accessing `this.state` after calling this method may return the old value.
1226:  *
1227:  * There is no guarantee that calls to `setState` will run synchronously,
1228:  * as they may eventually be batched together.  You can provide an optional
1229:  * callback that will be executed when the call to setState is actually
1230:  * completed.
1231:  *
1232:  * When a function is provided to setState, it will be called at some point in
1233:  * the future (not synchronously). It will be called with the up to date
1234:  * component arguments (state, props, context). These values can be different
1235:  * from this.* because your function may be called after receiveProps but before
1236:  * shouldComponentUpdate, and this new state, props, and context will not yet be
1237:  * assigned to this.
1238:  *
1239:  * @param {object|function} partialState Next partial state or function to
1240:  *        produce next partial state to be merged with current state.
1241:  * @param {?function} callback Called after state is updated.
1242:  * @final
1243:  * @protected
1244:  */
1245: ReactComponent.prototype.setState = function (partialState, callback) {
1246:   !(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null) ? "development" !== 'production' ? invariant(false, 'setState(...): takes an object of state variables to update or a function which returns an object of state variables.') : _prodInvariant('85') : void 0;
1247:   this.updater.enqueueSetState(this, partialState);
1248:   if (callback) {
1249:     this.updater.enqueueCallback(this, callback, 'setState');
1250:   }
1251: };

As explained here: The only place where you can assign this.state is the constructor.

Direct setting the state will not re-render a component, and this should be the idea behind the setState() method.

Also React may batch multiple setState() calls into a single update for performance.

Community
  • 1
  • 1
prosti
  • 42,291
  • 14
  • 186
  • 151