Django Rest Framework and React and Redux, Oh My!

49
Django Rest Framework and React and Redux, Oh My!

Transcript of Django Rest Framework and React and Redux, Oh My!

Page 1: Django Rest Framework and React and Redux, Oh My!

Django Rest Framework and React and Redux,

Oh My!

Page 2: Django Rest Framework and React and Redux, Oh My!

I’m Eric Palakovich Carr.Co-Founder & Chief Architect at

Previously:

Page 3: Django Rest Framework and React and Redux, Oh My!

What this talk is not

• A comprehensive tutorial

• A deep dive into how these technologies works

• You WILL need to go and learn this stuff on your own after this talk

Page 4: Django Rest Framework and React and Redux, Oh My!
Page 5: Django Rest Framework and React and Redux, Oh My!
Page 6: Django Rest Framework and React and Redux, Oh My!
Page 7: Django Rest Framework and React and Redux, Oh My!
Page 8: Django Rest Framework and React and Redux, Oh My!

{% extends "base.html" %}{% load staticfiles %}

{% block title %}Some Awesome Django Website{% endblock %}

{% block extrahead %} <link rel="stylesheet" href="{% static "some.css" %}"/> <link rel="stylesheet" href="{% static "even_more.css" %}"/>{% endblock %}

{% block body %} <!-- some content in Django template --> <div id="todolist"></div> <!-- more content in Django template -->{% endblock %}

Page 9: Django Rest Framework and React and Redux, Oh My!
Page 10: Django Rest Framework and React and Redux, Oh My!

Javascript Ecosystem

• We’ll be using NPM to manage your packages

• We’ll be using webpack to handle bundling our assets.

• We’ll be using scotch to burn away the memories of configuring the build system for our project.

Page 11: Django Rest Framework and React and Redux, Oh My!

in a nutshell• The pip & cheeseshop / pypi of javascript

• packages.json works like requirements.txt & setup.py

• `npm init` in directory with packages.json generates node_modules. Kinda like a virtualenv directory.

• packages.json also can act like your `manage.py` for your javascript code, but you populate it with custom commands.

Page 12: Django Rest Framework and React and Redux, Oh My!

Building for Javascript• Start coding your project, using `npm install some-package —

save` as you go. This creates and maintains your package.json.

• Setup the config file for your build tool (webpack.config.js, gulpfile.js, Gruntfile, etc)

• Add configs for Babel, minification, and other JS stuff

• Add configs LESS, SASS, and other CSS stuff

• Plus source mapping, tests, linters, sprite sheets, etc

• Run your tool to generate bundles, having them save into your static directory for Django to pick up.

Page 13: Django Rest Framework and React and Redux, Oh My!

{% extends "base.html" %}{% load staticfiles %}

{% block title %}Some Awesome Django Website{% endblock %}

{% block extrahead %} <link rel="stylesheet" href="{% static "bundle.css" %}"/> <link rel="stylesheet" href="{% static "some.css" %}"/> <link rel="stylesheet" href="{% static "even_more.css" %}"/>{% endblock %}

{% block body %} <!-- some content in Django template --> <div id="todolist"></div> <script src="{% static "bundle.js" %}"></script> <!-- more content in Django template -->{% endblock %}

Page 14: Django Rest Framework and React and Redux, Oh My!

{% extends "base.html" %}{% load staticfiles %}{% load render_bundle from webpack_loader %}

{% block title %}Some Awesome Django Website{% endblock %}

{% block extrahead %} <link rel="stylesheet" href="{% static "some.css" %}"/> <link rel="stylesheet" href="{% static "even_more.css" %}"/>{% endblock %}

{% block body %} <!-- some content in Django template --> <div id="todolist"></div> {% render_bundle 'main' 'js' %} <!-- more content in Django template -->{% endblock %}

Page 15: Django Rest Framework and React and Redux, Oh My!

DEMO

Page 16: Django Rest Framework and React and Redux, Oh My!
Page 17: Django Rest Framework and React and Redux, Oh My!

// index.js

import React from 'react';import ReactDOM from 'react-dom';import TodoHeader from './TodoHeader.jsx';

ReactDOM.render( ( <div className="todoWidget"> <TodoHeader listName="todos" /> </div> ), document.getElementById('todolist'));

Page 18: Django Rest Framework and React and Redux, Oh My!
Page 19: Django Rest Framework and React and Redux, Oh My!

// index.js

import React from 'react';import ReactDOM from 'react-dom';import TodoHeader from './TodoHeader.jsx';

ReactDOM.render( ( <div className="todoWidget"> <TodoHeader listName="todos" /> </div> ), document.getElementById('todolist'));

JSX

Page 20: Django Rest Framework and React and Redux, Oh My!

// TodoHeader.jsx

import React, { Component } from 'react';

export default class TodoHeader extends Component { render() { return ( <header className='todoHeadCmp'> <h1>{this.props.listName}</h1> </header> ); }}

Page 21: Django Rest Framework and React and Redux, Oh My!

JSX

// TodoHeader.jsx

import React, { Component } from 'react';

export default class TodoHeader extends Component { render() { return ( <header className='todoHeadCmp'> <h1>{this.props.listName}</h1> </header> ); }}

Page 22: Django Rest Framework and React and Redux, Oh My!

// TodoHeader.jsx

import React, { Component } from 'react';

export default class TodoHeader extends Component { render() { return React.createElement( "header", {className: "todoHeadCmp"}, React.createElement( "h1", null, this.props.listName, ) ); }}

Page 23: Django Rest Framework and React and Redux, Oh My!

export default class TodoTextInput extends Component { constructor(props, context) { super(props, context); this.state = { text: this.props.text || '' }; } handleSubmit(e) { const text = e.target.value.trim(); if (e.which === 13) { this.props.onSave(text); } } handleChange(e) { this.setState({ text: e.target.value }); } render() { return ( <input type='text' value={this.state.text} onChange={::this.handleChange} onKeyDown={::this.handleSubmit} /> ); }}

Page 24: Django Rest Framework and React and Redux, Oh My!

React Component Lifecycle• componentWillMount

• componentDidMount

• componentWillReceiveProps

• shouldComponentUpdate

• componentWillUpdate

• componentDidUpdate

• componentWillUnmount

Page 25: Django Rest Framework and React and Redux, Oh My!

Django Rest Framework• The Web browsable API is a huge usability win for your developers.

• Authentication policies including packages for OAuth1a and OAuth2.

• Serialization that supports both ORM and non-ORM data sources.

• Customizable all the way down - just use regular function-based views if you don't need the more powerful features.

• Extensive documentation, and great community support.

• Used and trusted by large companies such as Mozilla and Eventbrite.

Page 26: Django Rest Framework and React and Redux, Oh My!

Model->Serializer->ViewSetclass Todo(models.Model): text = models.CharField(max_length=300) marked = models.BooleanField(default=False) class TodoSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Todo fields = ('id', 'text', 'marked')

class TodoViewSet(viewsets.ModelViewSet): queryset = Todo.objects.all() serializer_class = TodoSerializer

Page 27: Django Rest Framework and React and Redux, Oh My!

Demo

Page 28: Django Rest Framework and React and Redux, Oh My!

Three Principles of Redux

• Single source of truth

• State is read-only

• Changes are made with pure functions

Page 29: Django Rest Framework and React and Redux, Oh My!

Redux State Tree / Store{ visibilityFilter: 'SHOW_ALL', todos: [ { text: 'Consider using Redux', completed: true, }, { text: 'Keep all state in a single tree', completed: false } ]}

Page 30: Django Rest Framework and React and Redux, Oh My!

Reducers{ visibilityFilter: 'SHOW_ALL', todos: [ { text: 'Consider using Redux', completed: true, }, { text: 'Keep all state in a single tree', completed: false } ]}

Page 31: Django Rest Framework and React and Redux, Oh My!

import * as types from '../constants/ActionTypes';

const initialState = [];export default function todos(state=initialState, action) { switch (action.type) { case types.ADD_TODO: return [...state, action.todo]; case types.DELETE_TODO: return state.filter(todo => todo.id !== action.id ); case types.EDIT_TODO: return state.map(todo => todo.id === action.todo.id ? action.todo : todo ); default: return state; }}

Page 32: Django Rest Framework and React and Redux, Oh My!
Page 33: Django Rest Framework and React and Redux, Oh My!

store.dispatch({ type: 'ADD_TODO', todo: { text: "Check how much time is left", marked: false }})

store.dispatch({ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_COMPLETED'})

Page 34: Django Rest Framework and React and Redux, Oh My!

Presentational Components• Are concerned with how things look.

• Use props for displaying everything

• Do not manage state at all

• Don’t emit actions, but may take callbacks that do via props

<MyComponent title=“No state, just props.” barLabels={["MD", "VA", "DE", "DC"]} barValues={[13.626332, 47.989636, 9.596008, 28.788024]}/>

Page 35: Django Rest Framework and React and Redux, Oh My!

Container Component• Are concerned with how things work.

• Responsible for providing data to presentational components via props

• Also responsible for handling state changes triggered inside a presentation component via callback prop. These state changes are often done via dispatching an action.

Page 36: Django Rest Framework and React and Redux, Oh My!

class TodoApp extends Component { componentDidMount() { this.props.actions.getTodos(); } render() { const { todos, actions } = this.props; return ( <div> <Header addTodo={actions.addTodo} /> <MainSection todos={todos} actions={actions} /> </div> ); }}function mapState(state) { return { todos: state.todos };}function mapDispatch(dispatch) { return { actions: bindActionCreators(TodoActions, dispatch) };}export default connect(mapState, mapDispatch)(TodoApp);

Page 37: Django Rest Framework and React and Redux, Oh My!

Wiring Redux to DRF

• Python package “django-js-reverse" for getting your url routes in your javascript

• NPM package “redux-promise”

Page 38: Django Rest Framework and React and Redux, Oh My!

import * as types from '../constants/ActionTypes';

function deleteTodo(id) { return fetch(Urls.todo_detail(id), { method: 'delete', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') }, }).then(() => ({ type: types.DELETE_TODO, id: id }));}

// In a component somewhere elsestore.dispatch(deleteTodo(this.props.todo.id))

Page 39: Django Rest Framework and React and Redux, Oh My!

import * as types from '../constants/ActionTypes';import * as api from ‘../path/to/MyApiLibrary';

function deleteTodo(id) { return api.deleteTodo(id).then(() => ({ type: types.DELETE_TODO, id: id }));}

// In a component somewhere elsestore.dispatch(deleteTodo(this.props.todo.id))

Page 40: Django Rest Framework and React and Redux, Oh My!

DEMO

Page 41: Django Rest Framework and React and Redux, Oh My!

Quick Recap i.e. TL;DR

Page 42: Django Rest Framework and React and Redux, Oh My!

You need a build tool to create bundles.

Webpack is nice for this.

Page 43: Django Rest Framework and React and Redux, Oh My!

{% extends "base.html" %}{% load staticfiles %}

{% block title %}Some Awesome Django Website{% endblock %}

{% block extrahead %} <link rel="stylesheet" href="{% static "bundle.css" %}"/> <link rel="stylesheet" href="{% static "some.css" %}"/> <link rel="stylesheet" href="{% static "even_more.css" %}"/>{% endblock %}

{% block body %} <!-- some content in Django template --> <div id="todolist"></div> <script src="{% static "bundle.js" %}"></script> <!-- more content in Django template -->{% endblock %}

Page 44: Django Rest Framework and React and Redux, Oh My!

// index.js

import React from 'react';import ReactDOM from 'react-dom';import TodoHeader from './TodoHeader.jsx';

ReactDOM.render( ( <div className="todoWidget"> <TodoHeader listName="todos" /> </div> ), document.getElementById('todolist'));

Page 45: Django Rest Framework and React and Redux, Oh My!

// TodoHeader.jsx

import React, { Component } from 'react';

export default class TodoHeader extends Component { render() { return ( <header className='todoHeadCmp'> <h1>{this.props.listName}</h1> </header> ); }}

Page 46: Django Rest Framework and React and Redux, Oh My!

class Todo(models.Model): text = models.CharField(max_length=300) marked = models.BooleanField(default=False) class TodoSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Todo fields = ('id', 'text', 'marked')

class TodoViewSet(viewsets.ModelViewSet): queryset = Todo.objects.all() serializer_class = TodoSerializer

Page 47: Django Rest Framework and React and Redux, Oh My!

import * as types from '../constants/ActionTypes';

const initialState = [];export default function todos(state=initialState, action) { switch (action.type) { case types.ADD_TODO: return [...state, action.todo]; case types.DELETE_TODO: return state.filter(todo => todo.id !== action.id ); case types.EDIT_TODO: return state.map(todo => todo.id === action.todo.id ? action.todo : todo ); default: return state; }}

Page 48: Django Rest Framework and React and Redux, Oh My!

import * as types from '../constants/ActionTypes';

function deleteTodo(id) { return fetch(Urls.todo_detail(id), { method: 'delete', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') }, }).then(() => ({ type: types.DELETE_TODO, id: id }));}

// In a component somewhere elsestore.dispatch(deleteTodo(this.props.todo.id))

Page 49: Django Rest Framework and React and Redux, Oh My!

Thanks!Eric Palakovich Carr

@bigsassy on twitter and github example repo at https://github.com/bigsassy/drf-react-redux