Commit Graph

7 Commits

Author SHA1 Message Date
Paul O’Shannessy 5967915ec4 Warn when calling setState & other methods at wrong time
Currently we use an invariant to prevent this code pattern. That is really
aggressive for something that doesn't actually put React in a bad state. This
diff replaces invariants with warnings and makes those code paths no-ops.
2015-02-09 17:04:13 -08:00
Paul O’Shannessy dae1dc6292 Upgrade to newer eslint, use esprima-fb
Eslint now allows us to use a different parser, which allows us to use
esprima-fb explicitly. This means we don't have to wait for espree to add
things like rest-param parsing. Though we do need eslint to upgrade its rules
to handle that AST.

I had hoped to enable parsing of our tests but we can't do that until we
change esprima-fb's XJS nodes to JSX.

While I was here, I also enabled the no-unused-vars rule since eslint
understands template strings. I also made the single quote enforcement
actually fail instead of just warn.
2015-02-09 14:27:28 -08:00
Lee Byron 9174501771 Merge pull request #2991 from leebyron/state-queue
Set state takes a function
2015-02-03 19:52:26 -05:00
Lee Byron 279b956c9b Set state takes a function
This diff enables setState to accept a function in addition to a state partial. If you provide a function, it will be called with the up-to-date `state, props, context` as arguments.

This enables some nicer syntax for complex setState patterns:

If setState is doing an increment and wants to guarantee atomicy, you need a function:

```
this.setState(state => ({ number: state.number + 1 }));
```

This atomicy is particularly important if setState is called multiple times in a single frame of execution as the result of complex user actions. It's a tricky bug to chase down and difficult to determine how to fix when you find it. The current pattern of reaching into _pendingState relies on an implementation detail.

In this example: props.doAction() may result in your ancestor re-rendering and providing you with new props. If setState is called directly with an object literal referencing `this.props`, it will use the *old* version of props, not the new value. Using a function solves for this case:

```
this.props.doAction();
this.setState((state, props) => ({ number: state.number * props.multiplier }));
```
2015-02-03 19:49:17 -05:00
Sebastian Markbage 2702281a13 Always trigger an update when a callback is enqueued.
enqueueCallbackInternal forgot to schedule an update.

We could rely on the implicit contract of enqueueElement to do it. However,
if we're currently outside a transaction, it'll flush synchronously. Before
we enqueue the callback. We could also enqueueCallback before we
enqueueElement, but that causes a fragile relationship between them. E.g.
enqueueElement should not need to schedule an update if it is the same
element.
2015-02-02 20:42:15 -08:00
Sebastian Markbage bebc568ceb Use Singleton LifeCycle State
All entry points are for reconciliation are within batching strategies.

Since we don't have any batching strategies with synchronous updates,
there can't be more than one life-cycle method on the stack at any given
time.

Therefore, it's safe to move the composite life cycle flag to a singleton.
This saves us some memory management.

I think that we can get rid of these life cycle states completely in the
future.
2015-01-27 01:19:31 -08:00
Sebastian Markbage ed7332c749 Extract setState, setProps etc into ReactUpdateQueue
I originally did this work so that we could allow setState to be called
before the internal ReactCompositeComponent was constructed. It's unlikely
that we'll go down that route now but this still seems like a better
abstraction. It communicates that this is not immediately updating an
object oriented class. It's just a queue which a minor optimization.
It also avoids bloating the ReactCompositeComponent file.

Since they both depend on the life cycle I break that out into a common
shared dependency. In a follow up I'll refactor the life-cycle management.
2015-01-27 00:55:25 -08:00