diff --git a/README.markdown b/README.markdown index 568cb20..74983d4 100644 --- a/README.markdown +++ b/README.markdown @@ -1,95 +1,83 @@ ## Contents -* [Stateless function](#stateless-function) -* [JSX spread attributes](#jsx-spread-attributes) -* [Destructuring arguments](#destructuring-arguments) -* [Conditional rendering](#conditional-rendering) -* [Children types](#children-types) -* [Array as children](#array-as-children) -* [Function as children](#function-as-children) -* [Render callback](#render-callback) -* [Children pass-through](#children-pass-through) -* [Proxy component](#proxy-component) -* [Style component](#style-component) -* [Event switch](#event-switch) -* [Layout component](#layout-component) -* [Container component](#container-component) -* [Higher-order component](#higher-order-component) -* [Prop hoisting](#prop-hoisting) - -## Stateless function - -[Stateless functions](https://facebook.github.io/react/docs/components-and-props.html) are a brilliant way to define highly reusable components. They don't hold `state` or `refs`; they're just functions. - -```js -const Greeting = () =>
Stateless functions are a brilliant way to define highly reusable components. They don’t hold state or refs; they’re just functions.
Stateless functions are a brilliant way to define highly reusable components. They don’t hold state; they’re just functions.
const Greeting = () => <div>Hi there!</div>
@@ -218,7 +226,7 @@ Children types
Functions may be used as children. However, it requires coordination with the parent component to be useful.
function
<div>
- {() => { return "hello world!"}()}
+ {(() => { return "hello world!"})()}
</div>
@@ -388,7 +396,9 @@ Style component
We can generate this output using a couple single-purpose components.
-const PrimaryBtn = props =>
+import classnames from 'classnames'
+
+const PrimaryBtn = props =>
<Btn {...props} primary />
const Btn = ({ className, primary, ...props }) =>
@@ -562,7 +572,97 @@ Higher-order component
This is a powerful pattern for providing fetching and providing data to any number of stateless function components.
+State hoisting
+Stateless functions don’t hold state (as the name implies).
+Events are changes in state.
+Their data needs to be passed to stateful container components parents.
+This is called “state hoisting”.
+It’s accomplished by passing a callback from a container component to a child component.
+class NameContainer extends React.Component {
+ render() {
+ return <Name onChange={newName => alert(newName)} />
+ }
+}
+
+const Name = ({ onChange }) =>
+ <input onChange={e => onChange(e.target.value)} />
+
+
+
+Name receives an onChange callback from NameContainer and calls on events.
+The alert above makes for a terse demo but it’s not changing state.
+Let’s change the internal state of NameContainer.
+class NameContainer extends React.Component {
+ constructor() {
+ super()
+ this.state = {name: ""}
+ }
+
+ render() {
+ return <Name onChange={newName => this.setState({name: newName})} />
+ }
+}
+
+
+
+The state is hoisted to the container, by the provided callback, where it’s used to update local state.
+This sets a nice clear boundary and maximizes the re-usability of stateless function.
+This pattern isn’t limited to stateless functions.
+Because stateless function don’t have lifecycle events,
+you’ll use this pattern with component classes as well.
+Controlled input is an important pattern to know for use with state hoisting
+(It’s best to process the event object on the stateful component)
+Controlled input
+It’s hard to talk about controlled inputs in the abstract.
+Let’s start with an uncontrolled (normal) input and go from there.
+<input type="text" />
+
+
+
+When you fiddle with this input in the browser, you see your changes.
+This is normal.
+A controlled input disallows the DOM mutations that make this possible.
+You set the value of the input in component-land and it doesn’t change in DOM-land.
+<input type="text" value="This won't change. Try it." />
+
+
+
+Obviously static inputs aren’t very useful to your users.
+So, we derive a value from state.
+class ControlledNameInput extends React.Component {
+ constructor() {
+ super()
+ this.state = {name: ""}
+ }
+
+ render() {
+ return <input type="text" value={this.state.name} />
+ }
+}
+
+
+
+Then, changing the input is a matter of changing component state.
+ return (
+ <input
+ value={this.state.name}
+ onChange={e => this.setState({ name: e.target.value })}
+ />
+ )
+
+
+
+This is a controlled input.
+It only updates the DOM when state has changed in our component.
+This is invaluable when creating consistent UIs.
+If you’re using stateless functions for form elements,
+read about using state hoisting to move new state up the component tree.
+