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

React/Redux Introduction

React/Redux Introduction

adwd

July 08, 2016
Tweet

More Decks by adwd

Other Decks in Programming

Transcript

  1. modules default import/export // MyApp.js import foo from './MyModule' //

    MyModule.js export default function foo () { ... }
  2. modules named import/export // MyApp.js import { foo, Bar, baz

    } from './MyModule' // MyModule.js export function foo () { ... } export class Bar { ... } export const baz = ... ࢀর: http://www.slideshare.net/teppeis/you-dont-know-es-modules
  3. class import MyModule, { myAdd, MyBaseClass } from './MyModule' class

    MyClass extends MyBaseClass { constructor() { } add = (a, b) => { return myAdd(a, b) } show = ({ a, b }) => { const { foo, bar } = a const { baz: { box = 1 }} = b console.log(MyModule.show({ foo, bar, box })) } } ※babel plugin transform-class-properties͕ඞཁ
  4. destructuring assignment import MyModule, { myAdd, MyBaseClass } from './MyModule'

    class MyClass extends MyBaseClass { constructor() { } add = (a, b) => { return myAdd(a, b) } show = ({ a, b }) => { const { foo, bar } = a const { baz: { box = 1 }} = b console.log(MyModule.show({ foo, bar, box })) } } show = (obj) => { const a = obj.a const b = obj.b const foo = a.foo const bar = a.bar const box = b.baz.box || 1 ... } 㱻
  5. https://facebook.github.io/react/html-jsx.html JSX class NewComponent extends React.Component { render() { return

    ( <div> {/* Hello world */} <div className="awesome" style={{border: '1px solid red'}}> <label htmlFor="name">Enter your name: </label> <input type="text" id="name" /> </div> <p>Enter your HTML here</p> </div> ); } } <!-- Hello world --> <div class="awesome" style="border: 1px solid red"> <label for="name">Enter your name: </label> <input type="text" id="name" /> </div> <p>Enter your HTML here</p>
  6. JSX class NewComponent extends React.Component { render() { const todos

    = ['eat', 'sleep'] return ( <div> <ul> { todos.map(item => <li>{item}</li>) } </ul> </div> ); } } <ul> <li>eat</li> <li>sleep</li> </ul>
  7. spread operator const list = [1, 2, 3] const list2

    = [ ...list, 4] // [1, 2, 3, 4] const obj = { a: 'foo', b: 1 } const obj2 = { ...obj, b: 2, c: 'bar' } // { a: 'foo', b: 2, c: 'bar' } const prop = { className: 'my-class', style: { color: ‘white’ } } const div = ( <div {...prop} > <p>foo bar</p> <div> ) // <div class="my-class" style="color: white;”> // <p>foo bar</p> // </div>
  8. αϯϓϧϓϩδΣΫτ • 3ͭͷTodoΞϓϦ • ReactͷΈ • React/Redux • React/Redux +

    REST API  5PEPͷδϨϯϚ w 3FEVYͰෳࡶͳঢ়ଶΛ؅ཧͰ͖Δˠαϯϓϧ ʹͦΜͳෳࡶͳͷΛग़ͤͳ͍ˠ݁ہ5PEP
  9. αϯϓϧϓϩδΣΫτ • React, Redux, React-router, Babel, ESLint, Webpackͳ Ͳ͕͍͍ײ͡ʹઃఆ͞ΕͨϘΠϥʔϓϨʔτ͔Βfork •

    https://github.com/davezuko/react-redux-starter-kit • มߋ఺: • react/reduxαϯϓϧίʔυͷ௥Ճɺmaterial-uiͷ௥ ՃͳͲ • forkݩ͸େن໛ͳॻ͖׵͕͑ਐΈશવҧͬͯ·͢ 
  10. αϯϓϧϓϩδΣΫτߏ੒ • src • layouts - ΞϓϦέʔγϣϯશମͰදࣔͯ͠ ͍Δόʔɺυϩϫʔίϯϙʔωϯτ • redux

    - reduxͷAction, Reducer • routes - react-routerͷϧʔςΟϯά • views - React/Reduxίϯϙʔωϯτ • server/api - json api 
  11. React࠷খߏ੒  // index.html <!DOCTYPE html> <html> <body> <div id="example"></div>

    <script type=“text/javascript" src=“/foo/bar/sample.js"/> </body> </html> // sample.js import React from 'react' import ReactDOM from 'react-dom' import MyComponent from './MyComponent' class Example extends React.Component { render () { return ( <div> <h1>Hello, world!</h1> <MyComponent message='Hello, world!' /> </div> ) } } ReactDOM.render( <Example />, document.getElementById('example') )
  12. React࠷খߏ੒  // index.html <!DOCTYPE html> <html> <body> <div id="example"></div>

    <script type=“text/javascript" src=“/foo/bar/sample.js"/> </body> </html> // sample.js import React from 'react' import ReactDOM from 'react-dom' import MyComponent from './MyComponent' class Example extends React.Component { render () { return ( <div> <h1>Hello, world!</h1> <MyComponent message='Hello, world!' /> </div> ) } } ReactDOM.render( <Example />, document.getElementById('example') ) React.Component
  13. React ίϯϙʔωϯτ  import React from 'react' class Sample extends

    React.Component { constructor (props) { super(props) this.state = { text: props.prefix + 'learn react' } } render () { return ( <p>{this.state.text}</p> ) } }
  14. React ίϯϙʔωϯτ  import React from 'react' class Sample extends

    React.Component { constructor (props) { super(props) this.state = { text: props.prefix + 'learn react' } } render () { return ( <p>{this.state.text}</p> ) } } React.ComponentΛܧঝ͠ɺ renderϝιουΛ࣋ͭΫϥε
  15. React ίϯϙʔωϯτ  import React from 'react' class Sample extends

    React.Component { constructor (props) { super(props) this.state = { text: props.prefix + 'learn react' } } render () { return ( <p>{this.state.text}</p> ) } } ֎෦͔ΒpropsΛड͚औΔ ಺෦ʹstateΛ࣋ͭ
  16. import React from 'react' class MyReactComponent extends React.Component { render

    () { return ( <div> <h1>This is My Component</h1> <div> {this.props.children} </div> </div> ) } } <MyReactComponent> <p>learn react</p> <p>learn flux</p> </MyReactComponent> props.children 
  17. import React from 'react' class MyReactComponent extends React.Component { render

    () { return ( <div> <h1>This is My Component</h1> <div> {this.props.children} </div> </div> ) } } <MyReactComponent> <p>learn react</p> <p>learn flux</p> </MyReactComponent> props.children  Reactίϯϙʔωϯτʹωετͨ͠ ཁૉ͸props.childrenʹೖΔ
  18. Components • TodoList • TodoΛstateͱͯ͠؅ཧ • TodoItem • TodoΛҰͭදࣔ •

    Todo࡟আϘλϯΛදࣔ  5PEP-JTU 5PEP*UFN ˣ5PEP-JTUίϯϙʔωϯτͷ TUBUFΛͦͷ··දࣔ
  19. TodoList state  { newTodo: '', todos: [ 'learn react’,

    'learn flux’, 'learn redux’ ] } • ௚઀DOMͷૢ࡞͸͠ͳ͍ɺ ঢ়ଶΛૢ࡞ͯ͠React͕ͦΕ Λඳը͢Δ
  20. TodoList render()  render () { return ( <div> <h1>React

    Sample</h1> <h2>Todos</h2> <input type='text' value={this.state.newTodo} onChange={this.changeText} /> <button onClick={this.addTodo}>add todo</button> { this.state.todos.map((text, index) => ( <TodoItem index={index} onRemove={this.deleteTodoItem} key={index}> {text} </TodoItem> )) } … </div> ) }
  21. TodoList render()  render () { return ( <div> <h1>React

    Sample</h1> <h2>Todos</h2> <input type='text' value={this.state.newTodo} onChange={this.changeText} /> <button onClick={this.addTodo}>add todo</button> { this.state.todos.map((text, index) => ( <TodoItem index={index} onRemove={this.deleteTodoItem} key={index}> {text} </TodoItem> )) } … </div> ) }
  22. import React, { Component } from 'react' export default class

    TodoList extends Component { constructor (props) { super(props) this.state = { newTodo: '', todos: [ 'learn react’, 'learn flux’, 'learn redux' ] } } ... } TodoList ίϯετϥΫλ 
  23. import React, { Component } from 'react' export default class

    TodoList extends Component { constructor (props) { super(props) this.state = { newTodo: '', todos: [ 'learn react’, 'learn flux’, 'learn redux' ] } } ... } TodoList ίϯετϥΫλ  ঢ়ଶͷॳظԽ
  24. TodoList ΫϥεϓϩύςΟ  changeText = (e) => { this.setState({ newTodo:

    e.target.value }) } addTodo = () => { const newTodo = this.state.newTodo this.setState({ newTodo: '', todos: [...this.state.todos, newTodo] }) } deleteTodoItem = (index) => { this.setState({ todos: this.state.todos.filter((todo, i) => i !== index) }) }
  25. changeText = (e) => { this.setState({ newTodo: e.target.value }) }

    addTodo = () => { const newTodo = this.state.newTodo this.setState({ newTodo: '', todos: [...this.state.todos, newTodo] }) } deleteTodoItem = (index) => { this.setState({ todos: this.state.todos.filter((todo, i) => i !== index) }) } TodoList ΫϥεϓϩύςΟ  this.setState stateͷࢦఆͨ͠ύε ͚ͩߋ৽͢Δ
  26. TodoItem.js  import React, { Component, PropTypes } from 'react'

    export default class TodoItem extends Component { static propTypes = { index: PropTypes.number, onRemove: PropTypes.func, children: PropTypes.oneOfType([ React.PropTypes.arrayOf(React.PropTypes.node), React.PropTypes.node ]) } render() { const { index, onRemove, children } = this.props; return ( <div> {`${index + 1}`}: {children} <input type='button' value='x' onClick={() => onRemove(index)} /> </div> ); } }
  27. TodoItem.js  import React, { Component, PropTypes } from 'react'

    export default class TodoItem extends Component { static propTypes = { index: PropTypes.number, onRemove: PropTypes.func, children: PropTypes.oneOfType([ React.PropTypes.arrayOf(React.PropTypes.node), React.PropTypes.node ]) } render() { const { index, onRemove, children } = this.props; return ( <div> {`${index + 1}`}: {children} <input type='button' value='x' onClick={() => onRemove(index)} /> </div> ); } } render()
  28. TodoItem.js  import React, { Component, PropTypes } from 'react'

    export default class TodoItem extends Component { static propTypes = { index: PropTypes.number, onRemove: PropTypes.func, children: PropTypes.oneOfType([ React.PropTypes.arrayOf(React.PropTypes.node), React.PropTypes.node ]) } render() { const { index, onRemove, children } = this.props; return ( <div> {`${index + 1}`}: {children} <input type='button' value='x' onClick={() => onRemove(index)} /> </div> ); } } propTypes: ࣮ߦ࣌ܕνΣοΫ
  29. Action • ΞϓϦέʔγϣϯͷঢ়ଶΛมԽͤ͞ΔΑ͏ ͳಈ࡞Λදݱͨ͠plain javascript object • ex) Todoͷ௥ՃɺAPIΞΫηεͷཁٻ/੒ޭ •

    typeϑΟʔϧυ͕ඞཁ  { "type": "ADD_TODO", "text": "Build my first Redux app" } { "type": "FETCH_USER_SUCCEEDED", "id": 1, "name": "Dan Abramov", }
  30. Reducer  const initalState = [] function todo(state = initalState,

    action) { switch (action.type) { case "ADD_TODO": return [...state, action.text] case "DELETE_TODO": return state.filter( (text, index) => index !== action.index ) default: return state } } state: [], action: { type: “ADD_TODO”, text: “hi” } ! nextState = reducer(state, action) ! nextState: [ “hi” ]
  31. Store API • createStore: (reducer) => Store • store.dispatch: ΞΫγϣϯͷ࣮ߦ

     import { createStore } from 'redux' import todo from './TodoReducer' const store = createStore(todo) store.dispatch({type: 'ADD_TODO', text: 'learn react'}) store.subscribe(() => { console.log(store.getState()) // [ ‘learn react’ ] })
  32. View • ͳΜͰ΋Α͍ • console.log, vue.js, Angular 1/2 … •

    Reactͷ৔߹͸ɺReactͱReduxͷ࿈ܞʹ react-reduxΛ࢖͏ 
  33. react-redux class TodoList extends React.Component { render() { <div> <button

    onClick={this.props.dispatch({ type: 'ADD_TODO', text: ‘learn react' })} /> { this.props.todo.map((text, index) => { <TodoItem key={index}> {text} </TodoItem> }) } </div> } }  store.dispatch store.getState().todo
  34. react-redux: connect  import { connect } from 'react-redux' class

    TodoList extends React.Component { render() { <div> <button onClick={this.props.dispatch({type: 'ADD_TODO', text: 'learn redux'})} /> { this.props.todo.map((text, index) => { <TodoItem key={index}>{text}</TodoItem> }) } </div> } } const connectedTodoList = connect( state => { todo: state.todo } )(TodoList) export default connectedTodoList { "todo": "...", "users": "...", "foo": "..." }
  35. react-redux: connect  import { connect } from 'react-redux' class

    TodoList extends React.Component { render() { <div> <button onClick={this.props.dispatch({type: 'ADD_TODO', text: 'learn redux'})} /> { this.props.todo.map((text, index) => { <TodoItem key={index}>{text}</TodoItem> }) } </div> } } const connectedTodoList = connect( state => { todo: state.todo } )(TodoList) export default connectedTodoList store.dispatch store.getState().todo ঢ়ଶΛද͢Jsonશମ͔Βtodo ෦෼͚ͩΛTodoListʹInject
  36. react-redux: Provider  import React from 'react' import { render

    } from 'react-dom' import App from './components/App' render( <App />, document.getElementById('root') ) import React from 'react' import { render } from 'react-dom' import { Provider } from 'react-redux' import { createStore } from 'redux' import todo from './reducers' import App from './components/App' const store = createStore(todo) render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
  37. Action (ActionCreator)  // src/redux/modules/todo.js export function addTodo () {

    return { type: 'ADD_TODO' } } export function removeTodo (index) { return { type: 'REMOVE_TODO', index } } export function editNewTodo (text) { return { type: 'EDIT_NEW_TODO', text } } • ͦ͜Β͡Ύ͏ʹ dispatch({ type: ‘ADD_TODO’ })Λॻ͔ͳ ͍Α͏ʹؔ਺ʹ͓ͯ͘͠ • dispatch(addTodo())
  38. // src/redux/modules/todo.js // Initial state const initialState = { newTodo:

    '', todos: [ 'learn react', 'learn flux', 'learn redux' ] } // Reducer export default function todoReducer (state = initialState, action) { switch (action.type) { case 'ADD_TODO': return { newTodo: '', todos: [...state.todos, state.newTodo] } case 'REMOVE_TODO': return { ...state, todos: state.todos.filter((todo, i) => i !== action.index) } case 'EDIT_NEW_TODO': return { ...state, newTodo: action.text } default: return state } } Reducer 
  39. Component  // src/views/ReduxSample/ReduxSample.js import { addTodo, removeTodo, editNewTodo }

    from ‘../../redux/modules/todo’ class ReduxSample extends Component { render () { const { todo: { newTodo, todos }, dispatch } = this.props return ( <div> <input type='text' value={newTodo} onChange={(e) => dispatch(editNewTodo(e.target.value)} /> ... </div> ) } } const ConnectedReduxSample = connect( state => ({todo: state.todo}) )(ReduxSample) export default ConnectedReduxSample
  40. Redux, react-redux ·ͱΊ • Redux • Flux, ୯ํ޲σʔλϑϩʔ • Action,

    Reducer, Store, View • react-redux • connectͰReduxͷঢ়ଶΛpropsʹinject • ProviderͰϧʔτͷίϯϙʔωϯτΛϥοϓ • ࣭໰ͳͲʁ 
  41. ඇಉظαϯϓϧ  server: localhost:3000/api/ • GET todos • POST todos/add

    • DELETE todos/:index source: server/api/todos.js 2 seconds delay
  42. Async Action  ඇಉظΞΫγϣϯ = dispatch => promiseͳؔ਺ // action

    creator const request = () => { type: 'REQUESTING' } const receive = (data) => { type: 'RECEIVED', data } // async action creator export function apiAccess() { return dispatch => { dispatch(request()) axios.get('api/sample') .then(response => { dispatch(receive(response.data)) }) .catch(e => { // error }) } }
  43. // action creator const request = () => { type:

    'REQUESTING' } const receive = (data) => { type: 'RECEIVED', data } // async action creator export function apiAccess() { return dispatch => { dispatch(request()) axios.get('api/sample') .then(response => { dispatch(receive(response.data)) }) .catch(e => { // error }) } } Async Action  ϦΫΤετૹ৴લʹ requestΞΫγϣϯ ϨεϙϯεΛड৴ͨ͠ͱ͜ΖͰ receiveΞΫγϣϯ
  44. Async Action (Reducer)  const initialState = { loading: false,

    todos = [] } function asyncReducer(state = initialState, action) { switch (action.type) { case 'REQUESTING': return { loading: true, todos = [] } case 'RECEIVED': return { loading: false, todos = action.data } default: return state } }
  45. Async Action (Component)  class AsyncComponent extends React.Component { componentDidMount()

    { this.props.dispatch(fetchTodos()) } render () { <div> { this.props.todo.loading ? <p>loading...</p> : <TodoList {...this.props.todo.todos} /> } </div> } } export default connect(state => { todo: state.todo })(AsyncComponent)
  46. Async Action (Component)  class AsyncComponent extends React.Component { componentDidMount()

    { this.props.dispatch(fetchTodos()) } render () { <div> { this.props.todo.loading ? <p>loading...</p> : <TodoList {...this.props.todo.todos} /> } </div> } } export default connect(state => { todo: state.todo })(AsyncComponent) loadingͰදࣔΛ੾Γସ͑ componentDidMountͰ APIʹϦΫΤετΛૹ৴
  47. ඇಉظॲཧ·ͱΊ • redux-thunk • ࠷ۙ͸redux-saga͕ਓؾΒ͍͠(?) • Netflix੡ͷredux-observableͱ͔΋ • ඇಉظɾ෭࡞༻Λѻ͏Redux middlewareͷઓࠃ࣌୅ײ

    • ΞΫηε։࢝ɾ׬ྃͰ2ճΞΫγϣϯΛ࣮ߦ • Storeͷঢ়ଶʹAPIΞΫηεঢ়ଶΛஔ͍͓ͯ͘ • ࣭໰ͳͲʁ 
  48. ओͳAPI  • <Router>, <Route> • ϧʔςΟϯάΛߦ͏ • <Route path=“/users”

    component={Users} /> • <Link> • <a href=“…” />ͷ໾ׂ • <Link to=“/users”>show users</Link> • withRouter • ReactίϯϙʔωϯτͷpropsʹrouterػೳΛInject • withRouter(MyComponent)
  49. routing  // src/routes/index.js import React from 'react' import {

    Route, IndexRoute } from 'react-router' import CoreLayout from 'layouts/CoreLayout/CoreLayout' import HomeView from 'views/HomeView/HomeView' import ReactSample from 'views/ReactSample' import ReduxSample from 'views/ReduxSample' import ReduxAsyncSample from 'views/ReduxAsyncSample' export default (store) => ( <Route path='/' component={CoreLayout}> <IndexRoute component={HomeView} /> <Route path='react' component={ReactSample} /> <Route path='redux' component={ReduxSample} /> <Route path='redux-async' component={ReduxAsyncSample} /> </Route> )
  50. routing  // src/routes/index.js import React from 'react' import {

    Route, IndexRoute } from 'react-router' import CoreLayout from 'layouts/CoreLayout/CoreLayout' import HomeView from 'views/HomeView/HomeView' import ReactSample from 'views/ReactSample' import ReduxSample from 'views/ReduxSample' import ReduxAsyncSample from 'views/ReduxAsyncSample' export default (store) => ( <Route path='/' component={CoreLayout}> <IndexRoute component={HomeView} /> <Route path='react' component={ReactSample} /> <Route path='redux' component={ReduxSample} /> <Route path='redux-async' component={ReduxAsyncSample} /> </Route> ) pathͰύεΛࢦఆ IndexRoute path=‘users/:id/edit’ ͳͲ΋Մೳ
  51. Component  // src/views/HomeView/HomeView.js import React, { Component, PropTypes }

    from 'react' import { connect } from 'react-redux' import { Link, withRouter } from 'react-router' export class HomeView extends Component { render () { const toReduxAsync = () => this.props.router.push('redux-async') return ( ... <Link to='react'><p>react sample</p></Link> <Link to='redux'><p>redux sample</p></Link> <button onClick={toReduxAsync}>redux-async sample</button> ... ) } } HomeView.propTypes = { router: PropTypes.shape({push: PropTypes.func}) } export default connect(state => state)(withRouter(HomeView))
  52. Component  // src/views/HomeView/HomeView.js import React, { Component, PropTypes }

    from 'react' import { connect } from 'react-redux' import { Link, withRouter } from 'react-router' export class HomeView extends Component { render () { const toReduxAsync = () => this.props.router.push('redux-async') return ( ... <Link to='react'><p>react sample</p></Link> <Link to='redux'><p>redux sample</p></Link> <button onClick={toReduxAsync}>redux-async sample</button> ... ) } } HomeView.propTypes = { router: PropTypes.shape({push: PropTypes.func}) } export default connect(state => state)(withRouter(HomeView)) <a />ͷ͔ΘΓʹ<Link />
  53. Component  // src/views/HomeView/HomeView.js import React, { Component, PropTypes }

    from 'react' import { connect } from 'react-redux' import { Link, withRouter } from 'react-router' export class HomeView extends Component { render () { const toReduxAsync = () => this.props.router.push('redux-async') return ( ... <Link to='react'><p>react sample</p></Link> <Link to='redux'><p>redux sample</p></Link> <button onClick={toReduxAsync}>redux-async sample</button> ... ) } } HomeView.propTypes = { router: PropTypes.shape({push: PropTypes.func}) } export default connect(state => state)(withRouter(HomeView)) router.push withRouterͰίϯϙʔωϯτͷ propsʹrouterΛInject
  54. αϯϓϧ  // tests/views/ReactSample.spec.js import React from 'react' import {

    shallow } from 'enzyme' import assert from 'power-assert' import ReactSample from 'views/ReactSample' import TodoItem from 'views/ReactSample/TodoItem' describe('ReactSample', function () { it('Should include an <h1> with \'React Sample\' text.', () => { const wrapper = shallow(<ReactSample />) assert(wrapper.childAt(0).type() === 'h1') assert(wrapper.childAt(0).text() === 'React Sample') }) it('should render three items', () => { const wrapper = shallow(<ReactSample />) assert(wrapper.find(TodoItem).length === 3) }) })
  55. shallow rendering  <div> <h1>React Sample</h1> <h2>Todos</h2> <input type='text' />

    <button>add todo</button> <TodoItem>{'learn react'}</TodoItem> <TodoItem>{'learn flux'}</TodoItem> <TodoItem>{'learn redux'}</TodoItem> <h3>state: </h3> <pre> ... </pre> </div> shallow(<TodoList />)
  56. shallow rendering  it('passes text to TodoItem', () => {

    const wrapper = shallow(<ReactSample />) assert.deepEqual(wrapper.state('todos'), ['learn react', 'learn flux', 'learn redux']) assert(wrapper.find(TodoItem).length === 3) assert(wrapper.find(TodoItem).at(0).props().children === 'learn react') assert(wrapper.find(TodoItem).at(1).props().children === 'learn flux') assert(wrapper.find(TodoItem).at(2).props().children === 'learn redux') })
  57. Full rendering (mount)  it('should render todo texts', () =>

    { const wrapper = mount(<ReactSample />) assert(wrapper.find('div').at(1).text() === '1: learn react ') assert(wrapper.find('div').at(2).text() === '2: learn flux ') assert(wrapper.find('div').at(3).text() === '3: learn redux ') })
  58. Full rendering (mount)  import React from 'react' import {

    mount } from 'enzyme' import { spy } from 'sinon' import assert from 'power-assert' import { ReduxAsyncSample } from 'views/ReduxAsyncSample/ReduxAsyncSample' describe('ReduxAsyncSample', () => { it('Should call fetch when componentDidMount', () => { spy(ReduxAsyncSample.prototype, 'componentDidMount'); const onFetch = spy() const wrapper = mount( <ReduxAsyncSample {...defaultProp} fetch={onFetch}/> ) assert(ReduxAsyncSample.prototype.componentDidMount.calledOnce) assert(onFetch.calledOnce) }) }) ˞XSJUF@NPVOU@UFTUϒϥϯνࢀর
  59. ·ͱΊ • React: ViewϥΠϒϥϦ • Redux: ΞϓϦέʔγϣϯͷঢ়ଶ؅ཧ • React-Redux: ReactͱReduxͷ࿈ܞ

    • Redux-Thunk: ඇಉظॲཧ • React-Router: URLϧʔςΟϯά • enzyme: ReactίϯϙʔωϯτςετϢʔςΟϦςΟ 
  60. reference • http://qiita.com/advent-calendar/2014/reactjs • ҰਓReact.js Advent Calendar 2014 • एׯݹ͍͚Ͳೖ໳ʹ

    • https://speakerdeck.com/koba04/the-state-of-react-dot-js-2016 • The state of React.js 2016 • React࠷৽ͷಈ޲ɺҰਓAdvent Calendar͔ΒͷΩϟονΞοϓ • https://facebook.github.io/react/docs • http://redux.js.org/ • ެࣜυΩϡϝϯτ͕ॆ࣮ • http://postd.cc/getting-started-with-tdd-in-react/ • ReactͰTDDʢςετۦಈ։ൃʣΛ࢝ΊΑ͏ : ؀ڥߏங͔Βςετ࡞੒ɺػ ೳ࣮૷·ͰͷৄղΨΠυ • ຊ౰ʹθϩ͔ΒTDDͰTodoΞϓϦΈ͍ͨͳͷΛ࡞ΕΔ 
  61. reference • Web+DB Press vol. 87 • @teppeis͞ΜͷES2015ಛू • http://www.slideshare.net/teppeis/effective-es6

    • @teppeis͞Μʹࡢ೥ฐࣾͷࣾ಺ษڧձͰൃද͍͍ͯͨͩͨ࣌͠ͷεϥΠυ • http://qiita.com/kuy • Redux, redux-sagaͷهࣄΛ୔ࢁॻ͍͍ͯΔ@kuy͞Μ • ൃԻ͸ʮΧΠʯ͞Μ 
  62. reference • http://redux.js.org/docs/basics/UsageWithReact.html • https://medium.com/@dan_abramov/smart-and-dumb- components-7ca2f9a7c7d0 • ίϯϙʔωϯτΛContainer/ViewͰ෼͚Δ • https://facebook.github.io/flux/docs/flux-utils.html#best-practices

    • facebook͕ڍ͛ͨfluxΞʔΩςΫνϟͰͷϕετϓϥΫςΟε • https://www.gitbook.com/book/tonyhb/redux-without-profanity/details • Dockerࣾ಺ͰReduxΛ࢖ͬͨϊ΢ϋ΢Λॻ͍ͨgitbook • StoreͱαʔόʔͷσʔλΛಉظͤ͞Δ࿩ • https://speakerdeck.com/chrisui/real-world-redux • Immutable.jsΛ࢖ͬͨStore, localStorageͰͷӬଓԽͳͲ • https://speakerdeck.com/joere/flowtype-with-flow • FlowtypeͰ੩తܕνΣοΫ  ͭ͘ΕΔˠΩϨΠʹεέʔϧ͢Δͭ͘Γʹ͢Δ