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 full-size slide

  2. Radoslav Stankov
    @rstankov

    http://rstankov.com

    http://github.com/rstankov

    View full-size slide

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

    View full-size slide

  4. ! React
    " Fiber
    # Redux
    $ GraphQL

    % Cool libraries

    View full-size slide

  5. ! React
    " Fiber
    # Redux
    $ GraphQL

    % Cool libraries
    &

    View full-size slide

  6. ! React
    " Fiber
    # Redux
    $ GraphQL

    % Cool libraries
    '

    View full-size slide

  7. ! React
    " Fiber
    # Redux
    $ GraphQL

    % Cool libraries

    View full-size slide

  8. React

    https://facebook.github.io/react


    View full-size slide

  9. Virtual Dom
    React
    Element
    React
    Element
    React
    Element
    React
    Element
    React
    Element

    View full-size slide

  10. Virtual Dom
    DOM
    Element
    DOM
    Element
    DOM
    Element
    DOM
    Element
    DOM
    Element

    View full-size slide

  11. Virtual Dom
    React
    Element
    React
    Element
    React
    Element
    React
    Element
    React
    Element

    View full-size slide

  12. 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 full-size slide


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


    View full-size slide


  14. Component

    View full-size slide


  15. Component
    Child Component

    View full-size slide


  16. Component
    Child Component
    Child Child Component

    View full-size slide


  17. Component
    Child Component
    Child Child Component

    Child Child … Child Component

    View full-size slide


  18. Component
    Child Component
    Child Child Component

    Child Child … Child Component
    Context

    View full-size slide


  19. Component
    Child Component
    Child Child Component

    Child Child … Child Component
    Context
    Context

    View full-size slide

  20. export default function SubmissionForm() {
    return (

    Speaker

    Name:



    Email:




    );
    }

    View full-size slide

  21. 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 full-size slide

  22. 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 full-size slide

  23. 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 full-size slide

  24. 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 full-size slide

  25. components/
    modules/
    pages/
    pages/Layout/
    utils/

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

    View full-size slide

  26. Redux

    http://redux.js.org


    View full-size slide

  27. React View
    Store

    View full-size slide

  28. Action
    React View
    Store

    View full-size slide

  29. Reducer
    Action
    React View
    Store

    View full-size slide

  30. Reducer
    Action
    React View
    New Store

    View full-size slide

  31. Reducer
    Action
    React View
    New Store

    View full-size slide

  32. Ducks: Redux Reducer Bundles

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


    View full-size slide

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

    View full-size slide

  34. 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 full-size slide

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

    View full-size slide

  36. 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 full-size slide

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

    View full-size slide

  38. 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 full-size slide

  39. 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 full-size slide

  40. 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 full-size slide

  41. 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 full-size slide

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

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

    {filter}

    ))}

    );
    }
    }

    View full-size slide

  43. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  47. 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 full-size slide

  48. 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 full-size slide


  49. http://graphql.org/


    View full-size slide

  50. POST /graphql

    View full-size slide


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

    View full-size slide


  52. 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 full-size slide

  53. 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 full-size slide

  54. 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 full-size slide

  55. 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 full-size slide

  56. 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 full-size slide


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

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

    View full-size slide


  58. http://www.apollodata.com/


    View full-size slide

  59. Header
    Media
    Recommended
    Posts
    Makers
    Discussion

    View full-size slide

  60. /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 full-size slide

  61. // 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 full-size slide

  62. // 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 full-size slide

  63. // 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 full-size slide

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

    View full-size slide

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


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

    View full-size slide

  66. ( 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 full-size slide

  67. ( 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 full-size slide

  68. ( 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 full-size slide

  69. ) 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 full-size slide

  70. ( 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 full-size slide

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

    View full-size slide