Upgrade to Pro — share decks privately, control downloads, hide ads and more …

React Unplugged

React Unplugged

A Q&A about React and friends. Presented at JS.Talks.

Links from presentation:

- slides
- https://facebook.github.io/react
- http://isfiberreadyyet.com
- https://www.youtube.com/watch?v=ZCuYPiUIONs
- http://redux.js.org
- https://github.com/erikras/ducks-modular-redux
- http://graphql.org/
- http://www.apollodata.com/
- styling
- https://github.com/css-modules/css-modules
- https://github.com/styled-components/styled-components
- ui
- https://github.com/Semantic-Org/Semantic-UI-React
- https://github.com/callemall/material-ui
- https://github.com/react-bootstrap/react-bootstrap
- https://github.com/gabrielbull/react-desktop
- https://github.com/palantir/blueprint
- https://github.com/grommet/grommet
- forms
- https://github.com/seeden/react-form-controlled
- https://github.com/erikras/redux-form
- https://github.com/25th-floor/revalidation
- https://github.com/codecks-io/react-reform
- https://github.com/tannerlinsley/react-form
- https://github.com/prometheusresearch/react-forms
- testing
- https://github.com/facebook/jest
- https://github.com/jasmine/jasmine
- https://github.com/airbnb/enzyme/
- https://github.com/chaijs/chai
- https://github.com/producthunt/chai-enzyme
- https://github.com/mochajs/mocha
- https://github.com/sinonjs/sinon
- react
- https://github.com/JedWatson/react-select
- https://github.com/ayrton/react-key-handler
- https://github.com/twitter-fabric/velocity-react
- https://github.com/ianstormtaylor/slate
- https://github.com/andreypopp/react-textarea-autosize
- https://github.com/brigade/react-waypoint
- https://github.com/acdlite/recompose
- https://github.com/cloudflare/react-gateway
- https://github.com/One-com/react-truncate
- https://github.com/react-component/progress
- https://github.com/react-component
- redux
- https://github.com/elgerlambert/redux-localstorage
- https://github.com/gaearon/redux-thunk
- https://github.com/redux-saga/redux-saga
- https://github.com/markdalgleish/redux-analytics
- https://www.npmjs.com/package/reselect
- https://www.npmjs.com/package/normalizr
- utilities
- https://github.com/lodash/lodash
- https://github.com/moment/moment
- https://github.com/JedWatson/classnames
- https://github.com/kolodny/immutability-helper

Radoslav Stankov

August 13, 2017
Tweet

More Decks by Radoslav Stankov

Other Decks in Technology

Transcript

  1. React Unplugged
    Radoslav Stankov 13/06/2017

    View Slide

  2. Radoslav Stankov
    @rstankov

    http://rstankov.com

    http://github.com/rstankov

    View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. https://speakerdeck.com/rstankov/react-unplugged

    View Slide

  7. View Slide

  8. View Slide

  9. View Slide

  10. ! React
    " Fiber
    # Redux
    $ GraphQL

    % Cool libraries

    View Slide

  11. ! React
    " Fiber
    # Redux
    $ GraphQL

    % Cool libraries
    &

    View Slide

  12. ! React
    " Fiber
    # Redux
    $ GraphQL

    % Cool libraries
    '

    View Slide

  13. ! React
    " Fiber
    # Redux
    $ GraphQL

    % Cool libraries

    View Slide

  14. View Slide

  15. React

    https://facebook.github.io/react


    View Slide

  16. Virtual DOM

    View Slide

  17. Virtual Dom
    React
    Element
    React
    Element
    React
    Element
    React
    Element
    React
    Element

    View Slide

  18. Virtual Dom
    DOM
    Element
    DOM
    Element
    DOM
    Element
    DOM
    Element
    DOM
    Element

    View Slide

  19. Virtual Dom
    React
    Element
    React
    Element
    React
    Element
    React
    Element
    React
    Element

    View Slide

  20. Virtual Dom
    React
    Element
    React
    Element
    React
    Element
    React
    Element
    React
    Element
    React
    Element
    React
    Element
    React
    Element
    React
    Element
    React
    Element
    DOM
    Element
    DOM
    Element
    DOM
    Element
    DOM
    Element
    DOM
    Element
    DOM
    Element
    DOM
    Element
    DOM
    Element
    DOM
    Element
    DOM
    Element

    View Slide

  21. Fiber

    View Slide

  22. View Slide


  23. https://www.youtube.com/watch?v=ZCuYPiUIONs


    View Slide

  24. Context

    View Slide


  25. Component

    View Slide


  26. Component
    Child Component

    View Slide


  27. Component
    Child Component
    Child Child Component

    View Slide


  28. Component
    Child Component
    Child Child Component

    Child Child … Child Component

    View Slide


  29. Component
    Child Component
    Child Child Component

    Child Child … Child Component
    Context

    View Slide


  30. Component
    Child Component
    Child Child Component

    Child Child … Child Component
    Context
    Context

    View Slide

  31. Forms

    View Slide

  32. export default function SubmissionForm() {
    return (

    Speaker

    Name:



    Email:




    );
    }

    View Slide

  33. class ExampleForm extends React.Component {
    state = { value: '' }
    handleChange = (event) => {
    this.setState({value: event.target.value});
    }
    handleSubmit = (event) => {
    e.preventDefault();
    remoteCall(this.target.value)/
    };
    render() {
    return (

    value={this.state.value}
    onChange={this.handleChange} />


    );
    }
    }

    View Slide

  34. class ExampleForm extends React.Component {
    state = { value: '' }
    handleChange = (event) => {
    this.setState({value: event.target.value});
    }
    handleSubmit = (event) => {
    e.preventDefault();
    remoteCall(this.target.value)/
    };
    render() {
    return (

    value={this.state.value}
    onChange={this.handleChange} />


    );
    }
    }
    Input change

    View Slide

  35. class ExampleForm extends React.Component {
    state = { value: '' }
    handleChange = (event) => {
    this.setState({value: event.target.value});
    }
    handleSubmit = (event) => {
    e.preventDefault();
    remoteCall(this.target.value)/
    };
    render() {
    return (

    value={this.state.value}
    onChange={this.handleChange} />


    );
    }
    }
    Input change

    handleChange
    setState

    View Slide

  36. class ExampleForm extends React.Component {
    state = { value: '' }
    handleChange = (event) => {
    this.setState({value: event.target.value});
    }
    handleSubmit = (event) => {
    e.preventDefault();
    remoteCall(this.target.value)/
    };
    render() {
    return (

    value={this.state.value}
    onChange={this.handleChange} />


    );
    }
    }
    Input change

    handleChange
    setState

    render
    New value

    View Slide

  37. components/
    modules/
    pages/
    pages/Layout/
    utils/

    config.js
    index.js
    paths.js
    routes.js

    View Slide

  38. Redux

    http://redux.js.org


    View Slide

  39. Store

    View Slide

  40. React View
    Store

    View Slide

  41. Action
    React View
    Store

    View Slide

  42. Reducer
    Action
    React View
    Store

    View Slide

  43. Reducer
    Action
    React View
    New Store

    View Slide

  44. Reducer
    Action
    React View
    New Store

    View Slide

  45. View Slide

  46. View Slide

  47. Ducks: Redux Reducer Bundles

    https://github.com/erikras/ducks-modular-redux


    View Slide

  48. function action() {
    return {
    type: ACTION
    };
    }
    redux-thunk

    View Slide

  49. function action() {
    return async (dispatch, getState) => {
    // do ... async stuff
    dispatch({ type: ACTION_1 });
    // do ... async stuff
    dispatch({ type: ACTION_2 });
    // ...so on
    };
    }
    redux-thunk

    View Slide

  50. import { createStore, applyMiddleware } from 'redux';
    import thunk from 'redux-thunk';
    import reducer from './reducers';
    const store = createStore(rootReducer, applyMiddleware(thunk));

    View Slide

  51. function changeFilter(filterName, api) {
    return async function(dispatch, getState) {
    if (getState().filter == filter) {
    return;
    }
    dispatch({ type: 'TODO/LOAD', filter: filter });
    const todos = await api.loadTodos({filter: filter});
    dispatch({ type: 'TODO/LOADED', todos: todos });
    };
    }

    View Slide

  52. this.props.filterChange(filterName, this.props.api);

    View Slide

  53. function changeFilter(filterName, api) {
    return async function(dispatch, getState) {
    if (getState().filter == filter) {
    return;
    }
    dispatch({ type: 'TODO/LOAD', filter: filter });
    const todos = await api.loadTodos({filter: filter});
    dispatch({ type: 'TODO/LOADED', todos: todos });
    };
    }

    View Slide

  54. import { createStore, applyMiddleware } from 'redux';
    import thunk from 'redux-thunk';
    import reducer from './reducers';
    import apiClient from './utils/apiClient';
    const api = apiClient();
    const store = createStore(rootReducer,
    applyMiddleware(thunk.withExtraArgument(api));

    View Slide

  55. function changeFilter(filterName, api) {
    return async function(dispatch, getState) {
    if (getState().filter == filter) {
    return;
    }
    dispatch({ type: 'TODO/LOAD', filter: filter });
    const todos = await api.loadTodos({filter: filter});
    dispatch({ type: 'TODO/LOADED', todos: todos });
    };
    }

    View Slide

  56. function changeFilter(filterName) {
    return async function(dispatch, getState, api) {
    if (getState().filter == filter) {
    return;
    }
    dispatch({ type: 'TODO/LOAD', filter: filter });
    const todos = await api.loadTodos({filter: filter});
    dispatch({ type: 'TODO/LOADED', todos: todos });
    };
    }

    View Slide

  57. class Filters extends React.Component {
    filterHander(filterName) {
    return () => {
    this.props.dispatch(changeFilter(filterName));
    };
    }
    render() {
    return (

    {Object.keys(FILTERS).map((filter) => (

    {filter}

    ))}

    );
    }
    }

    View Slide

  58. import createStore from 'tests/support/createStore';
    import factory from 'tests/support/factory';
    describe(changeFilter.name, () => {
    it('loads todos', () => {
    const store = createStore({ filter: 'all' });
    const todo = factory.todo();
    store.api.stub('loadTodos', [todo]);
    store.dispatch(changeFilter('completed'));
    expect(store.getState().filter).to.equal('completed');
    expect(store.getState().todos).to.deep.equal([todo]);
    });
    it('does not reload todos when filter is not changing', () => {
    const store = createStore({ filter: 'all' });
    const todo = factory.todo();
    store.api.stub('loadTodos', [todo]);
    store.dispatch(changeFilter('all'));
    expect(store.getState().todos).to.deep.equal([]);
    });
    });

    View Slide

  59. /modules/anchor.js
    /modules/context.js
    /modules/cookies.js
    /modules/currentUser.js
    /modules/notice.js
    /modules/seed.js
    /modules/visitedTopics.js

    View Slide

  60. modules/[reducer].js
    1. Action Constants
    2. Action Creators
    3. Reducer
    4. Selectors
    5. Other stuff ¯\_(ϑ)_/¯

    View Slide

  61. modules/[reducer].js
    1. Action Constants
    2. Action Creators
    3. Reducer
    4. Selectors
    5. Other stuff ¯\_(ϑ)_/¯

    View Slide

  62. import { createReducer } from 'ph/redux';
    import type { Dispatchable, Reducer } from 'ph/types/redux';
    import type { Notice } from 'ph/types/Notice';
    // Constants
    const RECEIVE_NOTICE = 'NOTICE/RECEIVE';
    // Actions
    export function receiveNotice(notice: Notice): Dispatchable {
    return { type: RECEIVE_NOTICE, payload: { notice } };
    }
    export function clearNotice(): Dispatchable {
    return { type: RECEIVE_NOTICE, payload: { notice: null } };
    }
    // Reducer

    const reducer: Reducer = function createReducer(null, {
    [RECEIVE_NOTICE]: (state, { payload: { notice } }) => notice,
    });

    export default reducer;

    View Slide

  63. import createTestStore from 'ph/createTestStore';
    import { clearNotice, receiveNotice } from 'ph/modules/notice';
    describe('notice', () => {
    const getState = (store) => store.getState().notice;
    describe(receiveNotice.name, () => {
    it('sets a notice object', () => {
    const store = createTestStore();
    const notice = { type: 'notice', message: 'submitted' }
    store.dispatch(receiveNotice(notice));
    expect(getState(store)).to.deep.equal(notice);
    });
    });
    describe(clearNotice.name, () => {
    it('sets a notice object', () => {
    const store = createTestStore();
    store.dispatch(clearNotice());
    expect(getState(store)).to.equal(null);
    });
    });
    });

    View Slide


  64. http://graphql.org/


    View Slide

  65. POST /graphql

    View Slide


  66. query {
    topic(id: 1) {
    id
    name
    description
    isFollowed
    image
    }
    }
    POST /graphql

    View Slide


  67. query {
    topic(id: 1) {
    id
    name
    description
    isFollowed
    image
    }
    }
    POST /graphql
    {
    "data": {
    "topic": {
    "id": 1,
    "name": "Tech",
    "description": "Hardware or
    "isFollowed": true,
    "image": "assets.producthun
    }
    }
    }

    View Slide

  68. query {
    topic(id: 1) {
    id
    ...Item
    }
    }
    fragment Item on Topic {
    id
    name
    description
    ...Button
    ...Image
    }
    fragment Button on Topic {
    id
    name
    isFollowed
    }
    fragment Image on Topic {
    image
    }
    POST /graphql
    {
    "data": {
    "topic": {
    "id": 1,
    "name": "Tech",
    "description": "Hardware or
    "isFollowed": true,
    "image": "assets.producthun
    }
    }
    }

    View Slide

  69. query {
    topic(id: 1) {
    id
    ...Item
    }
    }
    fragment Item on Topic {
    id
    name
    description
    ...Button
    ...Image
    }
    fragment Button on Topic {
    id
    name
    isFollowed
    }
    fragment Image on Topic {
    image
    }
    POST /graphql
    {
    "data": {
    "topic": {
    "id": 1,
    "name": "Tech",
    "description": "Hardware or
    "isFollowed": true,
    "image": "assets.producthun
    }
    }
    }

    View Slide

  70. query {
    topic(id: 1) {
    id
    ...Item
    }
    }
    fragment Item on Topic {
    id
    name
    description
    ...Button
    ...Image
    }
    fragment Button on Topic {
    id
    name
    isFollowed
    }
    fragment Image on Topic {
    image
    }
    POST /graphql
    {
    "data": {
    "topic": {
    "id": 1,
    "name": "Tech",
    "description": "Hardware or
    "isFollowed": true,
    "image": "assets.producthun
    }
    }
    }

    View Slide

  71. query {
    topic(id: 1) {
    id
    ...Item
    }
    }
    fragment Item on Topic {
    id
    name
    description
    ...Button
    ...Image
    }
    fragment Button on Topic {
    id
    name
    isFollowed
    }
    fragment Image on Topic {
    image
    }
    POST /graphql
    {
    "data": {
    "topic": {
    "id": 1,
    "name": "Tech",
    "description": "Hardware or
    "isFollowed": true,
    "image": "assets.producthun
    }
    }
    }

    View Slide


  72. mutation FollowTopic($input) {
    followTopic(input: $input) {
    node {
    id
    isFollowed
    }
    }
    }
    POST /graphql
    {
    "data": {

    "followTopic": {
    "node": {
    "id": 1,
    "isFollowed": true
    }
    }
    }
    }

    View Slide


  73. http://www.apollodata.com/


    View Slide

  74. View Slide

  75. View Slide

  76. View Slide

  77. Header
    Media
    Recommended
    Posts
    Makers
    Discussion

    View Slide

  78. /pages/Post/Discussion/Fragment.graphql
    /pages/Post/Discussion/index.js
    /pages/Post/Discussion/styles.css
    /pages/Post/RecommendedPosts/Fragment.graphql
    /pages/Post/RecommendedPosts/index.js
    /pages/Post/RecommendedPosts/styles.css
    /pages/Post/RecommendedPosts/Item/...
    /pages/Post/Header/...
    /pages/Post/Makers/...
    /pages/Post/Media/...
    /pages/Post/Query.graphql
    /pages/Post/index.js
    /pages/Post/styles.js

    View Slide

  79. // pages/Post/Discussion/Fragment.graphql

    fragment PostDiscussion on Post {
    comments {
    id
    created_at
    parent_comment_id
    state
    votes_count
    body
    user {
    id
    username
    name
    headline
    }
    }
    }

    View Slide

  80. // pages/Post/RecommendedPosts/Fragment.graphql
    #import "ph/pages/Post/RecommendedPosts/Item/Fragment.graphql"
    fragment PostRecommendedPosts on Post {
    recommended_posts(first: 10) {
    edges {
    node {
    ...PostRecommendedPostsItem
    }
    }
    }
    }

    View Slide

  81. // pages/Post/PostPage.graphql
    #import "ph/lib/meta/MetaTags.graphql"
    #import "./Discussion/Fragment.graphql"
    #import "./Header/Fragment.graphql"
    #import "./Makers/Fragment.graphql"
    #import "./Media/Fragment.graphql"
    #import "./RecommendedPosts/Fragment.graphql"
    query PostPage($id: String!) {
    post(id: $id) {
    id

    ...MetaTags
    ...PostDiscussion
    ...PostHeader
    ...PostMedia
    ...PostRecommendedPosts
    }
    }

    View Slide

  82. import QUERY from './Query.graphql';
    import { graphql } from 'react-apollo';
    // ...
    export default graphql(QUERY, {
    options: ({ params: { id } }) => ({
    variables: {
    id,
    },
    }),
    });

    View Slide

  83. View Slide

  84. ( https://github.com/css-modules/css-modules


    ) https://github.com/styled-components/styled-components
    Styling

    View Slide

  85. ( https://github.com/Semantic-Org/Semantic-UI-React
    ) https://github.com/callemall/material-ui
    * https://github.com/react-bootstrap/react-bootstrap
    + https://github.com/gabrielbull/react-desktop
    , https://github.com/palantir/blueprint
    - https://github.com/grommet/grommet
    UI

    View Slide

  86. ( https://github.com/seeden/react-form-controlled
    ) https://github.com/erikras/redux-form
    * https://github.com/25th-floor/revalidation
    + https://github.com/codecks-io/react-reform
    , https://github.com/tannerlinsley/react-form
    - https://github.com/prometheusresearch/react-forms
    Form

    View Slide

  87. ( https://github.com/facebook/jest
    ) https://github.com/jasmine/jasmine
    * https://github.com/airbnb/enzyme/
    + https://github.com/chaijs/chai
    , https://github.com/producthunt/chai-enzyme
    - https://github.com/mochajs/mocha
    . https://github.com/sinonjs/sinon
    Testing

    View Slide

  88. ) https://github.com/ayrton/react-key-handler
    * https://github.com/twitter-fabric/velocity-react
    + https://github.com/ianstormtaylor/slate
    - https://github.com/brigade/react-waypoint
    . https://github.com/acdlite/recompose
    / https://github.com/cloudflare/react-gateway
    0 https://github.com/One-com/react-truncate
    1 https://github.com/react-component
    React

    View Slide

  89. ( https://github.com/elgerlambert/redux-localstorage
    ) https://github.com/gaearon/redux-thunk
    * https://github.com/redux-saga/redux-saga
    + https://github.com/markdalgleish/redux-analytics
    , https://www.npmjs.com/package/reselect
    - https://www.npmjs.com/package/normalizr
    Redux

    View Slide

  90. ( https://github.com/lodash/lodash
    ) https://github.com/moment/moment
    * https://github.com/JedWatson/classnames
    + https://github.com/kolodny/immutability-helper
    Utilities

    View Slide

  91. View Slide