Slide 1

Slide 1 text

Understanding state in React Ben Alpert

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Multiple-choice widget JSON { "multipleSelect": true, "randomize": false, "choices": [ { "content": "$x$ is a rational number.", "correct": true }, { "content": "$x$ has an infinite, non-repeating decimal...", "correct": false }, { "content": "$x$ has a terminating decimal representation.", "correct": true }, ... ] }

Slide 6

Slide 6 text

Multiple-choice widget editor (Editor) var Editor = React.createClass({ render: function() { var choices = this.props.choices.map((choice, i) => ); return
{choices}
; }, handleDelete: function(i) { var choices = this.props.choices.slice(); choices.splice(i, 1); rerender(); }, serialize: function() { return { choices: this.props.choices.map((choice, i) => this.refs["choice" + i].serialize()) }; } });

Slide 7

Slide 7 text

Multiple choice widget editor (Choice) var Choice = React.createClass({ render: function() { return (
); }, serialize: function() { return { content: this.refs.content.getDOMNode().value }; } });

Slide 8

Slide 8 text

Let’s try it!

Slide 9

Slide 9 text

What just happened?

Slide 10

Slide 10 text

Problems in this implementation — React did the “wrong” DOM operations — When the DOM changes, component state doesn’t — If data changes, the DOM doesn’t update to match

Slide 11

Slide 11 text

React did the “wrong” DOM operations var oldChildren = [ , , ]; var newChildren = [ , ];

Slide 12

Slide 12 text

React did the “wrong” DOM operations React guesses (unintelligently) about what key is: var oldChildren = [ , , ]; var newChildren = [ , ]; …and deletes the last choice element.

Slide 13

Slide 13 text

React did the “wrong” DOM operations { "choices": [ { "content": "monkey", "key": 42 }, { "content": "gorilla", "key": 13 }, ... ] } var choices = this.props.choices.map((choice, i) => );

Slide 14

Slide 14 text

React did the “wrong” DOM operations Explicitly-specified keys: var oldChildren = [ , , ]; var newChildren = [ , ]; Now, React deletes the first element, as expected.

Slide 15

Slide 15 text

DOM and component state get out of sync

Slide 16

Slide 16 text

DOM and component state get out of sync

Slide 17

Slide 17 text

We need a single source of truth In this implementation, the DOM is usually the source of truth… except when it’s not. We don't know where to look to find what the value should be.

Slide 18

Slide 18 text

Reasons to keep state out of the DOM — Ties the view implementation to the data — Harder to show derived data — Slower

Slide 19

Slide 19 text

A gift from React: controlled components Previously: After converting to a controlled component:

Slide 20

Slide 20 text

A gift from React: controlled components Controlled components take a bit more work upfront, but they have several advantages: — Model and view never get out of sync — Easy to tell what's in the DOM based on your data — Easier to have data where you want it already (i.e., no need for serialize or ref) (Bonus: the demo works now even without keys.)

Slide 21

Slide 21 text

Best practices — Use key properly: if you don't have an appropriate key, add one to your data — Avoid keeping state in the DOM — Use controlled components — Read from the DOM only in event handlers — Think about where your source of truth is What do you get? Airtight UIs.

Slide 22

Slide 22 text

Thank you!