<FirstComponent meantForSomeChild='hi' />  <SecondComponent {...this.props} />  <ThirdComponent {...this.props} />  <FourthComponent {...this.props} />  <FifthComponent {...this.props} />  FinalComponent = (props) => <Button>{props.meantForSomeChild}</Button>  <ThirdComponent someSetting={props.justMe} />React
React Native
  import { AddPackingItem } from "packlist-components";
                           // VS
  import { AddPackingItem } from 'packlist-components/native'addItem, setNewItemText, value, clear
allItems
// Top level state
export default class App extends Component {
  state = {
    allItems: ["nachos", "burritos", "hot dog"],
    newItemName: ""
  };
// ...
}export default class App extends Component {
 // ...
 // Top level functions
  addItem = () => {
    this.setState(state => ({
      allItems: [...state.allItems, state.newItemName],
      newItemName: ""
    }));
  };
// ...
}//...
        <AddItems
          addItem={this.addItem}
          setNewItemText={this.setNewItemName}
          value={this.state.newItemName}
          clear={this.clear}
        />
        <ListItems allItems={this.state.allItems} />
//...NO THRILLS! It's simple right?
It's a pain, too.
// Top level state
export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      allItems: ["nachos", "burritos", "hot dog"],
      newItemName: "",
      addItem: this.addItem,
      setNewItemName: this.setNewItemName,
      clear: this.clear
    };
  }
// ...
}export default class App extends Component {
 // ...
 // Top level functions
  addItem = () => {
    this.setState(state => ({
      allItems: [...state.allItems, state.newItemName],
      newItemName: ""
    }));
  };
// ...
}//...
        <PackingContext.Provider value={this.state}>
          <AddItems />
          <ListItems />
        </PackingContext.Provider>
//...<PackingContext.Consumer>
  {({ newItemName, addItem, setNewItemName, clear }) => (
    <AddPackingItem
      addItem={addItem}
      setNewItemText={setNewItemName}
      value={newItemName}
      clear={clear}
    />
  )}
</PackingContext.Consumer>
import { PackingContext } from "Context/packingContext";export const PackingDefaults = {
  allItems: ["nacho", "burrito", "hotdog"],
  newItemName: ""
};
export const PackingContext = React.createContext({
  ...PackingDefaults
});
export const PackingDefaults = {
  allItems: ["nacho", "burrito", "hotdog"],
  newItemName: ""
};
export const PackingContext = React.createContext({
  ...PackingDefaults
});
What will this look like if we try to consume context outside of a Provider?
export const PackingDefaults = {
  allItems: ["nacho", "burrito", "hotdog"],
  newItemName: ""
};
export const PackingContext = React.createContext({
  ...PackingDefaults
});
What will this look like if we try to consume context outside of a Provider?
  export default class App extends Component {
    render() {
      return (
        <Provider store={store}>
          <div style={styles}>
            <h2>Welcome to Redux</h2>
            <AddItems />
            <ListItems />
          </div>
        </Provider>
      );
    }
  }SimpleList
  import { SimpleList } from "packlist-components";
  import { connect } from "react-redux";
  // What props will this component get from Global state?
  const mapStateToProps = state => ({ value: state.items.myItems });
  // HOC lane
  export default connect(mapStateToProps)(SimpleList);
The Higher Order Component trick
A higher order function is a function that takes a function as an argument or returns a function.
A higher order component is a function that takes a component as an argument AND returns a component.
SimpleList
  import { SimpleList } from "packlist-components";
  import { connect } from "react-redux";
  // What props will this component get from Global state?
  const mapStateToProps = state => ({ value: state.items.myItems });
  // HOC lane
  export default connect(mapStateToProps)(SimpleList);
We get a state-intelligent component wrapping our original component.
AddPackingItem
class AddItems extends Component {
  render () {
    const { dispatch, newItemName } = this.props
    return (
      <AddPackingItem
        addItem={() => dispatch(ItemActionCreators.addItem())}
        setNewItemText={(e) => 
          dispatch(ItemActionCreators.setNewItemName(e.target.value))
        }
        value={newItemName}
        clear={() => dispatch(ItemActionCreators.clear())}
      />
    )
  }
}
const mapStateToProps = state => ({newItemName: state.items.newItemName})
export default connect(mapStateToProps)(AddItems)
import { AddPackingItem } from "packlist-components";
import { ItemActionCreators } from "../Redux/Actions/items";
import { connect } from "react-redux";
const { setNewItemName, addItem, clear } = ItemActionCreators;
const mapDispatchToProps = {
  setNewItemText: e => setNewItemName(e.target.value),
  addItem,
  clear
};
const mapStateToProps = state => ({ value: state.items.newItemName });
export default connect(mapStateToProps, mapDispatchToProps)(AddPackingItem);
export const ItemsActions = {
  ADD_ITEM: 'ADD_ITEM',
  CLEAR: 'CLEAR',
  SET_NEW_ITEM_NAME: 'SET_NEW_ITEM_NAME'
}
export const ItemActionCreators = {
  addItem: () => ({ type: ItemsActions.ADD_ITEM }),
  clear: () => ({ type: ItemsActions.CLEAR}),
  setNewItemName: (value) => ({
      type: ItemsActions.SET_NEW_ITEM_NAME,
      value
  })
}const INITIAL_STATE = { myItems: ['nacho', 'burrito', 'hotdog'], 
  newItemName: ''}
export function reducer (state = INITIAL_STATE, action) {
  switch (action.type) {
    case ItemsActions.ADD_ITEM:
      return { ...state, myItems: [...state.myItems, state.newItemName],
        newItemName: ''
      }
    case ItemsActions.CLEAR:
      return { ...state, myItems: [] }
    case ItemsActions.SET_NEW_ITEM_NAME:
      return { ...state, newItemName: action.value }
    default:
      return state
  }
}import { createStore, applyMiddleware } from 'redux'
import RootReducer from '../Reducers'
let middleware = []
const baseStore = createStore(RootReducer, 
  applyMiddleware(...middleware))
export default initialState => {
  return baseStore
}export default class App extends Component {
  render() {
    return (
      <div style={styles}>
        <h2>Welcome to MobX</h2>
        <AddItems />
        <ListItems />
      </div>
    );
  }
}import React, { Component } from "react";
import { SimpleList } from "packlist-components";
import ListStore from "../Mobx/listStore";
import { observer } from "mobx-react";
@observer
export default class ListItems extends Component {
  render() {
    return <SimpleList value={[...ListStore.allItems]} />;
  }
}
@observer
export default class AddItems extends Component {
  render() {
    return (
      <AddPackingItem
        addItem={ListStore.addItem}
        setNewItemText={ListStore.setNewItemName}
        value={ListStore.newItemName}
        clear={ListStore.clear}
      />
    );
  }
}
class ObservableListStore {
  @observable allItems = ["nacho", "burrito", "hotdog"];
  @observable newItemName = "";
  addItem = () => {
    this.allItems.push(this.newItemName);
    this.newItemName = "";
  };
  clear = () => {
    this.allItems = [];
  };
  setNewItemName = e => {
    this.newItemName = e.target.value;
  };
}
The good suggestions and the bad suggestions!
  import { Provider } from "unstated";
  export default class App extends Component {
    render() {
      return (
        <Provider>
          <div style={styles}>
            <h2>Welcome to unstated</h2>
            <AddItems />
            <ListItems />
          </div>
        </Provider>
      );
    }
  }import React, { Component } from "react";
import ListContainer from "../Unstated/listContainer";
import { Subscribe } from "unstated";
import { SimpleList } from "packlist-components";
export default class ListItems extends Component {
  render() {
    return (
      <Subscribe to={[ListContainer]}>
        {list => <SimpleList value={list.state.allItems} />}
      </Subscribe>
    );
  }
}
      <Subscribe to={[ListContainer]}>
        {list => (
          <AddPackingItem
            addItem={list.addItem}
            setNewItemText={list.setNewItemName}
            value={list.state.newItemName}
            clear={list.clear}
          />
        )}
      </Subscribe>import { Container } from "unstated";
export default class ListContainer extends Container {
  state = {
    allItems: ["nachos", "burritos", "hot dog"],
    newItemName: ""
  };
  addItem = () => {
    this.setState(state => ({ allItems: [...state.allItems, state.newItemName],
    newItemName: "" }));
  };
  setNewItemName = event => {
    this.setState({ newItemName: event.target.value });
  };
  clear = () => {
    this.setState({ allItems: [] });
  };
}
import { Machine } from 'xstate';
const lightMachine = Machine({
  key: 'light',
  initial: 'green',
  states: {
    green: {
      on: {
        TIMER: 'yellow',
      }
    },
    yellow: {
      on: {
        TIMER: 'red',
      }
    },
    red: {
      on: {
        TIMER: 'green',
      }
    }
  }
});
const currentState = 'green';
const nextState = lightMachine
  .transition(currentState, 'TIMER')
  .value;
export default {
  initial: "idle",
  states: {
    idle: {
      on: {
        CLEAR: {
          idle: {
            actions: ["clear"],
            cond: isTrue
          }
        },
        SET_NEW_ITEM_NAME: {
          loaded: {
            actions: ["setNewItemName"]
          }
        }
      }
    },
    loaded: {
      on: {
        ADD_ITEM: {
          idle: {
            actions: ["addItem"]
          }
        },
        CLEAR: {
          loaded: {
            actions: ["clear"],
            cond: isTrue
          },
        },
        SET_NEW_ITEM_NAME: {
          loaded: {
            actions: ["setNewItemName"],
            cond: isNotEmpty
          },
          idle: {
            actions: ["setNewItemName"],
            cond: isEmpty
          }
        }
      }
    }
  }
};
<State is="idle">Current State 'idle'</State>
<State is="loaded">Current State 'loaded'</State>import { testStateMachine } from 'react-automata'
  import { App } from '../App'
  test('all state snapshots', () => {
    testStateMachine(App, { fixtures })
  })              <Mutation
                mutation={mutations.ADD_ITEMS}
                variables={{ newItem: this.state.newItem }}
              >
                {addItem => (
                  <button style={styles.addButton} onClick={addItem}>
                    Add Item
                  </button>
                )}
              </Mutation>
              <Mutation mutation={mutations.CLEAN_ITEMS}>
                {cleanItems => (
                  <button style={styles.cleanButton} onClick={cleanItems}>
                    Clean Items
                  </button>
                )}
              </Mutation>    <ApolloProvider client={client}>
      <div style={styles}>
        <h2>Welcome to Apollo-Link-State</h2>
        <AddItems />
        <ListItems />
      </div>
    </ApolloProvider>
@graphql(addItem, { name: "addItem" })
@graphql(clearItems, { name: "clearItems" })
@graphql(updateNewItem, { name: "updateNewItem" })
@graphql(newItem)
export default class AddItems extends Component {
  // ... just access props
  // like `this.props.addItem`
}const resolvers = {
  Mutation: {
    addItem: (_, _params, { cache }) => {
      const { items, newItem } = cache.readQuery({
        query: gql`
          {
            items @client
            newItem @client
          }
        `
      });
      const data = { items: items.concat([newItem]), newItem: "" };
      cache.writeData({ data });
      return null;
    },
    clearItems: (_, _params, { cache }) => {
      const data = { items: [] };
      cache.writeData({ data });
      return null;
    },
    updateNewItem: (_, { text }, { cache }) => {
      const data = { newItem: text }
      cache.writeData({ data });
      return null;
    },
  }
};import { gql } from "apollo-boost";
// Queries
export const items = gql`
  {
    items @client
  }
`;
export const newItem = gql`
  {
    newItem @client
  }
`;
Review them all!
~1hr to run
TO YOU!!!
https://slides.com/gantlaborde/react-state-museum