├── README.md ├── demos ├── dataNormalization.js ├── memoization.js ├── tree.js └── tree.test.js ├── index.html ├── main.js ├── package-lock.json ├── package.json └── talk ├── Provider.js ├── assets ├── graph-1.jpg ├── tree-1.jpg └── what-if-i-told-you.jpg ├── constants.js ├── deck.mdx ├── layouts └── BigCenter.js └── theme.js /README.md: -------------------------------------------------------------------------------- 1 | # Learning Backwards 2 | ## Learning Computer Science Through the Lens of React 3 | 4 | As someone without a degree in computer science and had to learn some of its concepts through an education of hard knocks and failed interviews, I thought it would be interesting to talk about the intersection of React concepts and computer science concepts. 5 | 6 | I have focused on a few topics for this talk, though you could easily go further with each one or find other intersections altogether. They are: 7 | 8 | * Big O Notation 9 | * Data Normalization 10 | * Memoization 11 | * Trees 12 | 13 | Hope you enjoy the talk and the rest of [Byteconf](https://byteconf.com/) 14 | 15 | -------------------------------------------------------------------------------- /demos/dataNormalization.js: -------------------------------------------------------------------------------- 1 | const normalizeByID = arr => 2 | arr.reduce((acc, cur) => { 3 | acc[cur.id] = cur 4 | return acc 5 | }, {}) 6 | 7 | const beings = [ 8 | { id: 1, name: 'Kyle' }, 9 | { id: 2, name: 'Anna' }, 10 | { id: 3, name: 'Krios' }, 11 | { id: 4, name: 'Tali' } 12 | ] 13 | 14 | const beingsByID = normalizeByID(beings) 15 | 16 | console.log(beingsByID) 17 | -------------------------------------------------------------------------------- /demos/memoization.js: -------------------------------------------------------------------------------- 1 | const memoize = fn => { 2 | const cache = {} 3 | 4 | return (...args) => { 5 | const stringifiedArgs = args.join('') 6 | 7 | if (cache[stringifiedArgs]) { 8 | console.log('From cache: ', cache[stringifiedArgs]) 9 | return cache[stringifiedArgs] 10 | } 11 | 12 | const result = fn(...args) 13 | cache[stringifiedArgs] = result 14 | 15 | console.log(result) 16 | console.log(cache) 17 | return result 18 | } 19 | } 20 | 21 | const add = (x, y) => x + y 22 | const memoAdd = memoize(add) 23 | 24 | memoAdd(1, 2) // 3 25 | memoAdd(2, 1) // 3 26 | memoAdd(1, 2) // From cache: 3 27 | -------------------------------------------------------------------------------- /demos/tree.js: -------------------------------------------------------------------------------- 1 | class Node { 2 | constructor(value) { 3 | this.value = value 4 | this.children = [] 5 | } 6 | 7 | addChild(value) { 8 | const node = new Node(value) 9 | this.children.push(node) 10 | return node 11 | } 12 | 13 | removeChild(index) { 14 | this.children.splice(index, 1) 15 | } 16 | } 17 | 18 | class Tree { 19 | constructor(value) { 20 | this.root = new Node(value) 21 | } 22 | } 23 | 24 | const areIdenticalNodes = (node1, node2) => { 25 | if ( 26 | node1.value !== node2.value || 27 | node1.children.length !== node2.children.length 28 | ) { 29 | return false 30 | } 31 | 32 | return node1.children.every((child, index) => 33 | areIdenticalNodes(child, node2.children[index]) 34 | ) 35 | } 36 | 37 | module.exports = { 38 | areIdenticalNodes, 39 | Node, 40 | Tree 41 | } 42 | -------------------------------------------------------------------------------- /demos/tree.test.js: -------------------------------------------------------------------------------- 1 | const { areIdenticalNodes, Node, Tree } = require('./tree') 2 | 3 | describe('Tree', () => { 4 | it('new Tree', () => { 5 | const tree = new Tree('foo') 6 | 7 | expect(tree.root.value).toEqual('foo') 8 | expect(tree.root.children.length).toEqual(0) 9 | }) 10 | }) 11 | 12 | describe('Node', () => { 13 | it('new node', () => { 14 | const node = new Node('foo') 15 | 16 | expect(node.value).toEqual('foo') 17 | expect(node.children.length).toEqual(0) 18 | }) 19 | 20 | it('addChild', () => { 21 | const node = new Node('foo') 22 | const child = node.addChild('bar') 23 | 24 | expect(node.children.length).toEqual(1) 25 | expect(node.children[0].value).toEqual('bar') 26 | }) 27 | 28 | it('removeChild', () => { 29 | const node = new Node('foo') 30 | const child = node.addChild('bar') 31 | node.removeChild(0) 32 | 33 | expect(node.children.length).toEqual(0) 34 | }) 35 | }) 36 | 37 | describe('areIdenticalNodes', () => { 38 | it('same value, no children', () => { 39 | const t1 = new Tree('foo') 40 | const t2 = new Tree('foo') 41 | 42 | expect(areIdenticalNodes(t1.root, t2.root)).toEqual(true) 43 | }) 44 | 45 | it('same value, same children', () => { 46 | const t1 = new Tree('foo') 47 | const t2 = new Tree('foo') 48 | 49 | t1.root.addChild('bar') 50 | t2.root.addChild('bar') 51 | 52 | expect(areIdenticalNodes(t1.root, t2.root)).toEqual(true) 53 | }) 54 | 55 | it('same value, same children length, diff children', () => { 56 | const t1 = new Tree('foo') 57 | const t2 = new Tree('foo') 58 | 59 | t1.root.addChild('bar') 60 | t2.root.addChild('baz') 61 | 62 | expect(areIdenticalNodes(t1.root, t2.root)).toEqual(false) 63 | }) 64 | 65 | it('same value, diff children length', () => { 66 | const t1 = new Tree('foo') 67 | const t2 = new Tree('foo') 68 | 69 | t1.root.addChild('bar') 70 | t1.root.addChild('baz') 71 | t2.root.addChild('bar') 72 | 73 | expect(areIdenticalNodes(t1.root, t2.root)).toEqual(false) 74 | }) 75 | 76 | it('grandchild level', () => { 77 | const t1 = new Tree('foo') 78 | const t2 = new Tree('foo') 79 | 80 | const c1 = t1.root.addChild('bar') 81 | const c2 = t2.root.addChild('bar') 82 | 83 | c1.addChild('baz') 84 | c2.addChild('baz') 85 | 86 | expect(areIdenticalNodes(t1.root, t2.root)).toEqual(true) 87 | }) 88 | }) 89 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 |¯\_(ツ)_/¯
Indulge me in a brief anecdote, please.
Learning some computer science won't hurt your career. It augments your day-to-day working knowledge.
It also can help you pass technical interviews more often.
Hopefully, better jobs => better life.
"Big O Notation" is a standard way of describing the worst-case performance of an algorithm in regards to time and/or space.
Good question!
An algorithm is a procedure for solving a problem. That's it. Nothing scary. It's a step-by-step way of going from start to finish.
const foo = () => 'foo'
44 |
45 | const first = arr => arr[0]
46 |
47 | const prop = (key, obj) => obj[key]
48 |
const arr = [1, 2, 3, 4, 5]
49 |
50 | arr.forEach()
51 | arr.map()
52 | arr.find()
53 | arr.reduce()
54 |
const arr = [1, 2, 3, 4, 5]
55 |
56 | const twoDArray = arr.map(n => arr.map(m => m * n))
57 | console.log(twoDArray)
58 | // [[1, 2, 3, 4, 5],
59 | // [2, 4, 6, 8, 10],
60 | // [3, 6, 9, 12, 15],
61 | // [4, 8, 12, 16, 20],
62 | // [5, 10, 15, 20, 25]]
63 |
const fib = n => {
64 | if (n < 2) {
65 | return 1
66 | }
67 |
68 | return fib(n - 1) + fib(n - 2)
69 | }
70 |
const binarySearch = (value, tree) => {
71 | const { left, right, value: rootValue } = tree.root
72 |
73 | return value === rootValue
74 | ? root
75 | : value < rootValue
76 | ? binarySearch(value, left)
77 | : binarySearch(value, right)
78 | }
79 |
We now recognize that certain data structures might be better suited for a task than others. One typical problem are find
s on lists. How can we overcome this?
// Create a normalizing function for IDs
80 |
81 | const normalizeByID = arr => arr.reduce((acc, cur) => {
82 | acc[cur.id] = cur
83 | return acc
84 | }, {})
85 |
const list = [
86 | { id: 1, name: 'Kyle' },
87 | { id: 2, name: 'Anna' },
88 | { id: 3, name: 'Krios' },
89 | { id: 4, name: 'Tali' }
90 | ]
91 |
92 | console.log(normalizeByID(list))
93 | // {
94 | // '1': { id: 1, name: 'Kyle' },
95 | // '2': { id: 2, name: 'Anna' },
96 | // '3': { id: 3, name: 'Krios' },
97 | // '4': { id: 4, name: 'Tali' }
98 | // }
99 |
We traded space for time.
We changed finding an item by ID from of O(n) to O(1).
Memoization is the use of a cache within a function to store previously calculated results for retrieval. We trade space for the time cost of recalculating the result again.
const memo = fn => {
100 | const cache = {}
101 |
102 | return (...args) => {
103 | const stringifiedArgs = args.join('')
104 |
105 | if (cache[stringifiedArgs]) {
106 | return cache[stringifiedArgs]
107 | }
108 |
109 | const result = fn(...args)
110 | cache[stringifiedArgs] = result
111 | return result
112 | }
113 | }
114 |
memo
accepts a function as an argumentReselect
uses memoization for faster state updatesA tree is a graph data structure comprised of nodes with any number of children and no cycles.
A graph is a data structure made up of nodes with "edges" between them. A cycle is when several nodes all point to one another.
A tree only has parent and child nodes, with no child nodes pointing to other child nodes.
Every website* in the world is a tree data structure
*I haven't visited them all, so don't quote me on this 😝<html>
115 | <head>
116 | <title>Learning Backwards</title>
117 | </head>
118 | <body>
119 | <p>Ain't it <strong>awesome</strong> learning backwards!</p>
120 | </body>
121 | </html>
122 |
{
123 | value: html,
124 | children: [
125 | { value: head, children: [
126 | { value: title, children: ['Learning Backwards'] }
127 | ]},
128 | { value: body, children: [
129 | { value: p, children: [
130 | "Ain't it ",
131 | { value: strong, children: ['awesome'] },
132 | ' learning backwards!'
133 | ]}
134 | ]}
135 | ]
136 | }
137 |
React.createElement('html', {}, [
138 | React.createElement('head', {}, [
139 | React.createElement('title', {}, [
140 | 'Learning Backwards'
141 | ])
142 | ]),
143 | React.createElement('body', {}, [
144 | React.creactElement('p', {}, [
145 | "Ain't it ",
146 | React.createElement('strong', {}, [
147 | 'awesome'
148 | ]),
149 | ' learning backwards!'
150 | ])
151 | ])
152 | ])
153 |
const inOrderTraversal = visit => treeRoot => {
154 | inOrderTraversal(visit)(treeRoot.left)
155 | visit(treeRoot)
156 | inOrderTraversal(visit)(treeRoot.right)
157 | }
158 |
const inOrderTraversal = visit => treeRoot => {
159 | visit(treeRoot)
160 | inOrderTraversal(visit)(treeRoot.left)
161 | inOrderTraversal(visit)(treeRoot.right)
162 | }
163 |
const inOrderTraversal = visit => treeRoot => {
164 | inOrderTraversal(visit)(treeRoot.left)
165 | inOrderTraversal(visit)(treeRoot.right)
166 | visit(treeRoot)
167 | }
168 |
Ain't it awesome learning backwards!
331 | 332 | 333 | ``` 334 | 335 | --- 336 | 337 | export default FullScreenCode 338 | 339 | ```javascript 340 | { 341 | value: html, 342 | children: [ 343 | { value: head, children: [ 344 | { value: title, children: ['Learning Backwards'] } 345 | ]}, 346 | { value: body, children: [ 347 | { value: p, children: [ 348 | "Ain't it ", 349 | { value: strong, children: ['awesome'] }, 350 | ' learning backwards!' 351 | ]} 352 | ]} 353 | ] 354 | } 355 | ``` 356 | 357 | --- 358 | 359 | export default FullScreenCode 360 | 361 | ```javascript 362 | React.createElement('html', {}, [ 363 | React.createElement('head', {}, [ 364 | React.createElement('title', {}, [ 365 | 'Learning Backwards' 366 | ]) 367 | ]), 368 | React.createElement('body', {}, [ 369 | React.creactElement('p', {}, [ 370 | "Ain't it ", 371 | React.createElement('strong', {}, [ 372 | 'awesome' 373 | ]), 374 | ' learning backwards!' 375 | ]) 376 | ]) 377 | ]) 378 | ``` 379 | 380 | --- 381 | 382 | # Live Coding Time!!! 383 | ## Kinda. Live for me. Taped for you. 384 | 385 | --- 386 | 387 | ## Binary Tree Traversal - In Order 388 | 389 | ```javascript 390 | const inOrderTraversal = visit => treeRoot => { 391 | inOrderTraversal(visit)(treeRoot.left) 392 | visit(treeRoot) 393 | inOrderTraversal(visit)(treeRoot.right) 394 | } 395 | ``` 396 | 397 | --- 398 | 399 | ## Binary Tree Traversal - Pre Order 400 | 401 | ```javascript 402 | const inOrderTraversal = visit => treeRoot => { 403 | visit(treeRoot) 404 | inOrderTraversal(visit)(treeRoot.left) 405 | inOrderTraversal(visit)(treeRoot.right) 406 | } 407 | ``` 408 | 409 | --- 410 | 411 | ## Binary Tree Traversal - Post Order 412 | 413 | ```javascript 414 | const inOrderTraversal = visit => treeRoot => { 415 | inOrderTraversal(visit)(treeRoot.left) 416 | inOrderTraversal(visit)(treeRoot.right) 417 | visit(treeRoot) 418 | } 419 | ``` 420 | 421 | --- 422 | 423 | ## How might this help us in React? 424 | 425 | - Debugging 426 | - Optimizing Renders 427 | - Recursive functions for React elements 428 | - Compound Components 429 | 430 | --- 431 | 432 | # Takeaways! 433 | ## aka Kyle's pre-conclusion ramblings 😝 434 | 435 | --- 436 | 437 | ## Resources 438 | 439 | * [Big O Cheat Sheet](http://bigocheatsheet.com/) 440 | * [Four Semesters of CS in Six Hours](https://btholt.github.io/four-semesters-of-cs/) 441 | * [Four Semesters of CS in Six Hours - Part 2](https://btholt.github.io/four-semesters-of-cs-part-two/) 442 | * [Cracking the Coding Interview](https://www.amazon.com/Cracking-Coding-Interview-Programming-Questions/dp/0984782850) 443 | 444 | --- 445 | 446 | # Thank You!!! 447 | ## Byteconf for hosting and you for listening! 448 | 449 | --- 450 | 451 | # Find me on... 452 | 453 | - [Twitter](https://twitter.com/kyleshevlin) 454 | - [egghead](https://egghead.io/instructors/kyle-shevlin) 455 | - [Twitch](https://www.twitch.tv/kyleshevlin) 456 | - [My Newsletter](https://buttondown.email/kyleshevlin) 457 | - [Github](https://github.com/kyleshevlin) 458 | -------------------------------------------------------------------------------- /talk/layouts/BigCenter.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default ({ children }) => ( 4 |