@jsx React.DOM enables XML syntax known as jsx.React module allows for creation and rendering of React components.msg is a React component instance, constructed using XML syntax.React.renderComponent renders the react content into the document.
/**
* @jsx React.DOM
*/
var React = require('React');
var msg =
<div class="outerDiv">
<span>hello</span>
</div>;
React.renderComponent(msg, document.getElementById('someId'));
The previous example was very straightforward except for the use of
XML syntax. The inclusion of @jsx React.DOM accomplishes
two things.
div and span are
functions that are in scope. In fact, all standard DOM tags
(such as img and ul are also treated
this way).
Obviously, javascript isn't the most attractive way to specify
declarative structures. The XML syntax will be used for the
remainder of this tutorial. Additionally, require calls and calls to
React.renderComponent will be ommited from
examples.
/**
* @jsx React.DOM
*/
var React = require('React');
var div = React.DOM.div;
var span = React.DOM.span;
var msg =
div({
className:"outerDiv",
children: [
span({
children: ['hello']
})
]
});
React.renderComponent(msg, document.getElementById('someId'));
React.initializeTouchEvents(true);
React.renderComponent(yourComponent, document.getElementById('someId'));
jsx syntax out of the box.jsx.
jsx syntax.div and span.
@jsx
React.DOM in the first docblock comment. All DOM components
support children in addition to standard DOM
attributes class, href, etc. The only thing to
remember, is that DOM attributes should be expressed in camelCase (onClick).
var fbUrl = "www.facebook.com";
var btn = <a href={fbUrl} class="butButton"> Visit Facebook </a>;
Typeahead and LeftNav
ReactCompositeComponents are "custom" components.
Composite components are not automatically "in scope" like
ReactDOMComponents. The tag name will need to be
defined as a variable in the scope. By convention, each
ReactCompositeComponent is a commonJS module.
Remember: Composite components must be in scope before use.
// Suppose Typeahead is an instnace of ReactCompositeComponent
var Typeahead = require('Typeahead');
// Typeahead has chosen to accept a "selected" attribute
// and children.
var myTypeahead=
<Typeahead selected="jordanjcw" >
{something.dataset}
</Typeahead>;
The following tutorial shows you how to define a new component type
called LikeToggler.
The LikeToggler will render an image and allow the user to
toggle the like status on the image. See Image 1 to the right for a
screenshot of the final result.
To create a new component type, we must specify:
Note: React favors composition over inheritance as a means of abstraction.
All of the plumbing for this tutorial has been set up for you in www/trunk. Simply edit the main tutorial javascript file and refresh your browser. (See Figure 6 to the right).
vim ~/www/html/js/components/ReactTutorial/ReactTutorial.js Open http://yourSandbox.facebook.com/intern/reacttutorial
Here, we create a new component called LikeToggler by
making a call to React.createClass. We pass a
javascript object that describes the methods to include in the new
class. render is the most important method, and is the
only one required. It describes the structure of your
component.
Remember: render should never have side effects.
Remember:
When returning jsx blocks, parenthesis guard
against ASI.
var LikeToggler = React.createClass({
render: function() {
return (
<div>
Welcome to the tutorial. Implement LikeToggler here!
</div>
);
}
});
render
function to match Figure 8.
var LikeToggler = React.createClass({
render: function() {
return (
<div class="LikeToggler">
<h5>Toggle your like.</h5>
<img src="https://graph.facebook.com/boo/picture" />
</div>
);
}
});
Let's make our app interactive! We'll allow the user to "Like" Boo through our component's interface. In order to do so, we'll want to track that state in our component internally.
Add a method calledgetInitialState to your component.
getInitialState should return a javascript object that
represents your component's initial state. We'll return an object
with likes set to false to indicate that
the user does not initially like Boo.
var LikeToggler = React.createClass({
getInitialState: function() { // <--New method here
return {likes: false};
},
render: function() {
return (
<div class="LikeToggler">
<h5>Toggle your like.</h5>
<img src="https://graph.facebook.com/boo/picture" />
</div>
);
}
});
span in your rendered output.
div in your rendered output to display the
current like status.
doToggle.
onClick attribute of the span to
be the new member.
doToggle handler to
confirm that your click is wired up correctly.
Remember: Always specify DOM attributes in their camelCase form.
var LikeToggler = React.createClass({
getInitialState: function() {
return {likes: false};
},
doToggle: function(event) {
// What shall we do here?
},
render: function() {
return (
<div class="LikeToggler">
<h5>Toggle your like.</h5>
<img src="https://graph.facebook.com/boo/picture" />
<div class="btn" onClick={this.doToggle}>
Like Boo
</div>
<div></div>
</div>
);
}
});
We need to accomplish the following when the user clicks.
likes field.div from
"Like Boo" to "Unlike Boo"span from empty
to "You like this."You might be tempted to search for the DOM nodes whos content you
wish to change, and force them to change. However, React provides a
more powerful abstraction to help you express the dynamics of changing
content over time. In react, we change our state fields via a call to
this.setState. Then, we express render
as a function of this.state at all points in time
- for an arbitrary state. Nothing else is needed!
Here's how that plays out in our example:
First, We set our next state's likes field to an
inversion/toggle of our current likes (Line 8).
Then, we make our like toggler button's content is an expression
that is a function or an arbitrary state:
<div class="btn" onClick={this.doToggle}>
{this.state.likes ? 'Unlike Boo' : 'Like Boo'}
</div>
Finally, we do the same with the span's content
<span>{this.state.likes ? 'You Like This.' : ''}</span>
React guarantees that when state is updated, these expressions
will be reevaluated and the underlying DOM structures will be reconciled.
To be clear, you can put any expression in terms of
this.state inside of render. There are
essentially no limitations. Consider the
render function to be a constraint that you specify
and that React will always satisfy.
var LikeToggler = React.createClass({
getInitialState: function() {
return {likes: false};
},
doToggle: function(event) {
this.setState({likes: !this.state.likes});
},
render: function() {
return (
<div class="LikeToggler">
<h5>Toggle your like.</h5>
<img src="https://graph.facebook.com/boo/picture" />
<span>{this.state.likes ? 'You Like This.' : ''}</span>
<div class="btn" onClick={this.doToggle}>
{this.state.likes ? 'Unlike Boo' : 'Like Boo'}
</div>
</div>
);
}
});
There's something lacking from our LikeToggler
component. Components such as div and span
accept attributes (such as href and
class), but currently, our component is instantiated as
follows, without attributes:
var myLikeToggler = <LikeToggler />;
Now suppose we want to control the entity being liked.
var myLikeToggler =
<LikeToggler
name="Boo"
imgSrc="http://graph.facebook.com/boo/picture"
/>;
This is extremely easy to do! Inside of the render
method, all attributes are accessible through a special member called
this.props. See the Figure 12 for the complete component.
It's worth taking a close look at the last span's
content. Recognize how the content depends on two separate pieces of
data, from two completely different locations (props
and state). Any time either of these data
change, the content of that span will always be
reconciled to the expression specified.
<div class="btn" onClick={this.doToggle}>
{(this.state.likes ? 'Unlike ' : 'Like ') + this.props.name}
</div>
var LikeToggler = React.createClass({
getInitialState: function() {
return {likes: false};
},
doToggle: function(event) {
this.setState({likes: !this.state.likes});
},
render: function() {
return (
<div class="LikeToggler">
<h5>Toggle your like.</h5>
<img src={this.props.imgSrc} />
<span>{this.state.likes ? 'You Like This.' : ''}</span>
<div class="btn" onClick={this.doToggle}>
{(this.state.likes ? 'Unlike ' : 'Like ') + this.props.name}
</div>
</div>
);
}
});
Note: The terms attributes and props used interchangably.
When you look at render, anywhere you see tags
<...> there exists an implication of "ownership".
Meaning that whatever instance renders, also "owns"
those components that are rendered. For example, in Figure 13, we
define a new component type LikeTogglerWrapper that is
composed of the LikeToggler that we previously
defined.
The LikeTogglerWrapper instance clearly owns the
LikeToggler component. The
LikeTogglerWrapper is only thing thing that determines
the props (or attributes) of the
LikeToggler. Furthermore, it is the only thing that
determines its very existence.
var LikeTogglerWrapper = React.createClass({
render: function() {
return (
<LikeToggler
imgSrc="https://graph.facebook.com//picture"
name="jwalke"
/>
);
}
});
Clearly, our new component is somehow "in charge" of the
LikeToggler, so it makes sense to use the term "owner".
However, there's still one thing it's not in charge of - the
internal state of the LikeToggler.
state and props are both simple packages
of information, but they are distinct in one critical aspect
- control.
this.state. You are the only one that
should ever update this.state. You never need to ask
permission to update your own state because you are in control of
it.
this.props. Your
props are controlled by the same entity that instantiated
you - that is to say that your this.props are
controlled by your owner.
Therefore, you should never update your own this.props.
The description of this.state
describes traditional encapsulation. But the description of
this.props is less familiar. We've described
this.props as public, but in a more restricted way than
in traditional OO design. Our props can be controlled from outside
of our component instance, because they can only be controlled from
outside of our component instance, by the owner of us. See
Figure 14 for an illustration of data flow, ownerhip and control.
These two conventions ensure that all data in the system has a single owner. If you wish to control information that you do not own, you must find a way to inform the owner of that information that you wish to change it. In other programming paradigms, these authoritatively owned packages of information may be refered to as models.
Remember:
A component instance must be the only one to update its own
this.state via a call to
this.setState({..}) and nothing else should update
its this.state.
Remember:
A component must never update its own this.props. Only
a component's "owner" (or the Reactive system) should ever
update its props.
Examine Figure 14. It helps to think of this.props and
this.state as streams of information that your
render function operates on in order to return your
component's structure. render always
sees the freshest values of these streams. You do not need to
perform any setup to make this happen. You do not need to subscribe
to any changes. The React core makes sure that
render correctly describes your component's structure
whenever this.props or this.state may have
changed.
We said that render always "sees the freshest values"
of this.props and this.state, but how does
this
happen? In particular, how does a component always see the freshest
values of this.props? If a component cannot update its
own this.props, then who does? The answer is that
changes to this.props will be the result of a call to
setState() at a higher level in the component
hierarchy. From the point of state update, the reactive system will
ensure that the component subtree is brought up to date by updating
the props of components below it in the hierarchy.
There are some exceptional cases, where it doesn't make sense to
merely rely on state changes to update props, but those cases are
rare. In those cases, React allows a way to attach a reference
handle to individual components returned from render
and to directly tell that component to update its props, bypassing
the standard reactive data flow. In doing so, we're not violating
the rules mentioned above. The component that specifies the
reference handles, and invokes `updateProps` is the rightful "owner"
of the referenced component and has full authority to update the
props directly.
Note: This will be further documented in a new tutorial section discussing "refs" (not yet written).
requireing
them. DOM components (such as <div />) are
always in scope and do not need to be required.
onClick).
React.createClass to create a new custom component class.
render as a function of an arbitrary
this.state and this.props.
render, you observe attributes by
referencing this.props.attributeName.
render, you observe internal state by
referencing this.states.stateFieldName.
render always sees the most up-to-date values for
this.state and this.props.
this.setState({...}).
this.state.
this.props.
this.state should only ever contain serializable data (think "JSON")
and you should never stuff react component instances into
this.state.