From bc3e3b00ffb52e2d0dbf61cd926259cfa5b01bb9 Mon Sep 17 00:00:00 2001 From: DevStar411112 Date: Sat, 3 Dec 2016 08:15:38 -0800 Subject: [PATCH 01/14] add: state hoisting --- README.markdown | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- index.html | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index 568cb20..9e6d302 100644 --- a/README.markdown +++ b/README.markdown @@ -15,7 +15,7 @@ * [Layout component](#layout-component) * [Container component](#container-component) * [Higher-order component](#higher-order-component) -* [Prop hoisting](#prop-hoisting) +* [State hoisting](#state-hoisting) ## Stateless function @@ -630,3 +630,50 @@ const ConnectedMyComponent = Connect(Greeting) ``` This is a powerful pattern for providing fetching and providing data to any number of [stateless function components](#stateless-function). + +## State hoisting +[Stateless functions](#stateless-function) don't hold state (as the name implies). + +Events are changes in state. +Their data needs to be passed to stateful [container components](#container-component) parents. + +This is called "state hoisting". +It's accomplished by passing a callback from a container component to a child component. + +```js +class NameContainer extends React.Component { + render() { + return alert(newName)} /> + } +} + +const Name = ({ onChange }) => + 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`. + +```js +class NameContainer extends React.Component { + constructor() { + super() + this.state = {name: ""} + } + + render() { + return 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. +Given that a stateless function can't keep `refs` or use lifecycle events, +you'll find yourself using this with component classes as well. + +*(It's best to process the event object on the stateful component)* diff --git a/index.html b/index.html index f40e396..882e819 100644 --- a/index.html +++ b/index.html @@ -47,7 +47,7 @@

Contents

  • Layout component
  • Container component
  • Higher-order component
  • -
  • Prop hoisting
  • +
  • State hoisting
  • Stateless function

    Stateless functions are a brilliant way to define highly reusable components. They don’t hold state or refs; they’re just functions.

    @@ -562,6 +562,45 @@

    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. +Given that a stateless function can’t keep refs or use lifecycle events, +you’ll find yourself using this with component classes as well.

    +

    (It’s best to process the event object on the stateful component)

    - \ No newline at end of file + From 3a3a1b9ec512b2f9e5f9d38b453b014a2ba11d42 Mon Sep 17 00:00:00 2001 From: DevStar411112 Date: Fri, 14 Apr 2017 13:13:45 +0200 Subject: [PATCH 05/14] Fixed small typo in controlled input example --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index fbf4512..af0378b 100644 --- a/README.markdown +++ b/README.markdown @@ -722,7 +722,7 @@ Then, changing the input is a matter of changing component state. return ( this.setState(e.target.value)} + onChange={e => this.setState({ name: e.target.value })} /> ) ``` From dbe80c7e332502ffa90dd8f53f87f17a7b6f127d Mon Sep 17 00:00:00 2001 From: DevStar411112 Date: Thu, 11 May 2017 13:45:02 -0700 Subject: [PATCH 06/14] legal: add copyright notice --- index.html | 5 +++++ scripts/_index.html | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/index.html b/index.html index 0390968..ea36000 100644 --- a/index.html +++ b/index.html @@ -649,6 +649,11 @@

    Controlled input

    If you’re using stateless functions for form elements, read about using state hoisting to move new state up the component tree.

    +
    +

    + © Copyright 2017, Michael Chan +

    +
    - + \ No newline at end of file diff --git a/scripts/_index.html b/scripts/_index.html index b3c671a..fa553f9 100644 --- a/scripts/_index.html +++ b/scripts/_index.html @@ -23,17 +23,36 @@

    React Patterns - [expect errors. report - on github] + [on github] - chantastic + +

    <%= content %>

    - © Copyright 2017, Michael Chan + © Copyright 2017, Michael Chan

    From 4bbc2dcc6f7205ef8320891f5a6be0894e5612bd Mon Sep 17 00:00:00 2001 From: DevStar411112 Date: Thu, 11 May 2017 15:36:57 -0700 Subject: [PATCH 08/14] ad: update ad link with trackers --- index.html | 2 +- scripts/_index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 3b891b4..1be2860 100644 --- a/index.html +++ b/index.html @@ -27,7 +27,7 @@

    - +
    Learn React Ad diff --git a/scripts/_index.html b/scripts/_index.html index fa553f9..c37b7a6 100644 --- a/scripts/_index.html +++ b/scripts/_index.html @@ -27,7 +27,7 @@

    - +
    Learn React Ad From 2dc5107f413c3f17faf74c94efbb111aa5964684 Mon Sep 17 00:00:00 2001 From: DevStar411112 Date: Tue, 20 Jun 2017 11:48:26 +0000 Subject: [PATCH 09/14] Import classnames before using it --- README.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index af0378b..47182f2 100644 --- a/README.markdown +++ b/README.markdown @@ -2,7 +2,6 @@ * [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) @@ -428,6 +427,8 @@ Say we have a button. It uses classes to be styled as a "primary" button. We can generate this output using a couple single-purpose components. ```js +import classnames from 'classnames' + const PrimaryBtn = props => From 06b6b909f00546fb14922b4b434340bff2fb26c0 Mon Sep 17 00:00:00 2001 From: DevStar411112 Date: Tue, 20 Jun 2017 11:51:18 +0000 Subject: [PATCH 10/14] get back one of the missing menu items --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 47182f2..a8a0055 100644 --- a/README.markdown +++ b/README.markdown @@ -2,6 +2,7 @@ * [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) From d288b6c184024caa4c6751919a370c15691fe424 Mon Sep 17 00:00:00 2001 From: DevStar411112 Date: Fri, 10 Nov 2017 16:21:39 +0800 Subject: [PATCH 11/14] Correct a syntax error --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index a8a0055..037e398 100644 --- a/README.markdown +++ b/README.markdown @@ -222,7 +222,7 @@ Functions may be used as children. However, it requires [coordination with the p ```js
    - {() => { return "hello world!"}()} + {(() => { return "hello world!"})()}
    ``` From 4ba4f00d4a03040eae2c3c682d11f331eff07378 Mon Sep 17 00:00:00 2001 From: DevStar411112 Date: Sat, 11 Nov 2017 18:24:54 +0100 Subject: [PATCH 12/14] Add a title tag The title is not necessary but the default display of websites without titles isn't great on some browsers. --- index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 1be2860..033ef32 100644 --- a/index.html +++ b/index.html @@ -2,6 +2,7 @@ + React Patterns