-
Notifications
You must be signed in to change notification settings - Fork 0
/
fe-be.txt
1558 lines (1450 loc) · 76.9 KB
/
fe-be.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1.Internet working
Gửi request->ISP->DNS server(tìm IP) trả về ISP->host
Host nhận dc IP -> server trả về HTML,css,javascript
Ktra kết nối từ host->server
Hop Number - 3RTT(gửi 3 gói riêng biệt) - IP đích
Nếu hop > 150ms(mà k phả qua biển) thì là lâu, có vấn đề
Dấu '*' có thể do timeout hoặc do firewall
*Cách mà 1 website load nhanh hơn:
-Vị trí của server
-Ít việc truyền-nhận page/data (trips)
-Size của HTML/CSS/javascript (https://developers.google.com/speed/pagespeed/insights/?hl=vi)
JQuery:thư viện giúp JS viết đơn giản, sạch, k lo lắng trên các browser khác nhau
LAMP stack: Linux Apache MySQL, PHP
Apache:Phần mềm host phục vụ các file
Node server:NodeJS,Express
Database:PortgreJS,mongoDB
*Program
+allocate memory
+parse and execute
2. HTML5
<!DOCTYPE html> : ns vs browser web hiện đang sử dụng html5
nested tag: tag trong tag
<html lang='en'>:document language (https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
<meta name="viewport" content="width=device-width, initial-scale=1.0">: responsive web design
<meta charset='UTF-8'/>: bỏ vào <head> (https://internetingishard.com/html-and-css/links-and-images/html-character-sets-no-utf-8-304820.png)
//It’s different from the language of your document in that it only affects how the letters themselves are rendered, not the language of the content
*không thể viết <,>,& vào doc nếu chưa encode
-> <p>There are three reserved characters in HTML: < > and &. You
should always use HTML entities for these three characters.</p>
<strong>:bold
<em>:emphasis
<ol><li>:list có thứ tự
<ul><li>:list k có thứ tự
<br>:line beak(tag tự đóng)
<hr>:horizoline(tag tự đóng)
<img src="[source]" width="...px" height="...px">(tag tự đóng)
*HTML5 không cần đóng vd <br/> --> <br>
<a href="" target="_blank/_self"></a>:anchor tag->dùng để link tới doc(page) khác. href:hypertext reference
*Với tên file là index.html server sẽ trả về file đó đầu tiên
Relative path: vd <a href="test/about.html">...</a>
Absolute path: vd <a href="http://....">...</a>
<form method="GET/POST" action=""> Tạo các trường input, submit,....
//Với GET: lưu thông tin form trên đường link để gửi tới server: vd: ?[value of attibute name(property)]=...&... -> Dấu "?" thể hiện việc có data vào URL
//Với POST:lưu thông tin form vào body của request
//action: vd: action="action.php"-> khi submit gửi tới server, chạy đoạn script action.php này
<input type="[text/checkbox/password/email/date/submit/reset/radio]" value="" min="1->..." required> //required để bát buộc ng dùng phải điền vào
//min: số ký tự tối thiểu phải nhập
<select name="">//drop down list
<option value="">...
</option>
</select>
</form>
*name attibute để phân định gia đình(có thể chỉ 1 trong chúng dc nhấn như radio button). Là key của input và thứ nhập vào là value
VD như radio button khi dùng chúng sẽ được tick riêng lẻ,muốn 1 tick thì cái còn lại sẽ trống và ngược lại?
-><input type="radio" name="">...
<div>
<span>
inline emlement vs block element
senmatic element HTML5
*Trở về 1 file: ../
3.CSS
link trong <head>:
<link rel="stylesheet" type="text/css" href="style.css">
Selector {
property:value;
}
background-image:url(... . jpg/www.....com)
background-size:
list-syle:none
display:block/inline-block/
class="class1 class2"(class 2 là con của class1)-> .class1/.class2
id="..."->#...
element1, element2: chọn tag 1 và 2
element1 elemment2: chọn 2 ở trong 1
element1 > element2: chọn element2 MUST có cha là element 1
element1 + element2: chọn element2 ngay sau element 1
element:hover -> chỏ chuột vào thì thành
element:last-child/first-child
value !important: Đè lên tất cả những thay đổi->thay đổi duy nhất và cuối cùng
Ngoài chạy từ trên xuống, effect còn dựa vào:
Win-out selector:specificity(specificity calculator),importance,source order
float:left/right ->prop của img nhằm đưa ảnh về phía trái hoặc phải và content bao quanh
*để clear float tại 1 element nào đó dùng clear:both
Critical render path: K render dc trừ khi nhận css hay file liên quan
->Giải quyết: file style(font) riêng,minifying CSS(CSS minifier: xóa space,enter)
flexbox: bỏ tất cả trong container. Activate bằng cách display:flex
transition(chuyển dạng): all(tất cả property có thể chuyển đổi dc)(hoặc transform) 1s(trong thời gian 1s) thay đổi từ từ
transition: [property] [duration] [timing-function] [delay];
*The transition effect will start when the specified CSS property(or all) changes value
vd: transition: 1s ease-in-out;
+img:hover{transform:scale(1.1)}. tranform nếu k có transition sẽ thay đổi ngay lập tức
Với những property mới muốn chạy trên IE hay trình duyệt khác dùng vd: -moz-box-shadow/-ms-box-shadow(IE)/-webkit(safari,chrome)/-o-(opera)
*và vẫn phải thêm property vào cuối những cái trên
*<meta charset="utf-8"/>
*<meta name="viewport" content="width=device-width, initial-scale=1.0,shrink-to-fit=no">:cho ta biết web sẽ hoạt động thên mobile và ta có thể zoom
*cách để background image căn chỉnh đẹp,flexible ở giữa:
background: url("./header.jpg") no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size:cover;
*rem: là đơn vị tham chiếu tỷ lệ so với phần tử gốc của website ở đây là thẻ <html> dựa vào giá trị của thuộc tính font-size
em: là đơn vị tham chiếu tỷ lệ so với phần tử cha trực tiếp chứa nó hoặc chính nó dựa vào giá trị của thuộc tính là font-size
GRID:
-bỏ tất cả content trong 1 class duy nhất và thực hiện CSS:
-display:grid
-grid-template-columns: bao nhiêu col muốn dùm(có thể dùng % nhưng nên dùng fr(fraction))
VD:grid-template-columns:300px 300px (300px,2 col)
grid-template-columns:1fr 1fr
hoặc ta có thể dùng grid-template-columns:repeat([số lần(col)],[tỷ lệ]) VD grid-template-columns:repeat(3,1fr)
hoặc để value là auto để tự fill chỗ trống
*grid-template-columns:repeat(auto-fill,minmax([min],[max])) để content tự động lấp đầy chỗ trống
VD:grid-template-columns:repeat(auto-fill,minmax(200px,1fr)):tự động căn chỉnh, khi chạm giới hạn nhỏ nhất (<200px) sẽ fill bằng max
-grid-gap: khoảng cách giữa 2 content VD:grid-gap:20px
-grid-template-rows: bao nhiêu row muốn dùm(có thể dùng % nhưng nên dùng fr(fraction))
*Nếu content<value grid dc define sẽ repeat(trở về ban đầu)
VD: 3 content mà ta chỉ định nghĩa grid-template-rows:1fr 2r thì content số 3 sẽ về 1fr
-justify-items:start/end/scretch (điều chỉnh item theo axis theo row)
-align-items:start/end/scretch (điều chỉnh item theo axis theo col)
*Để tạo grid khác size nhau:
-Tạo các class bên trong(giống/khác nhau)
-grid-column-start:line của col bắt đầu VD:1 thì sẽ là line dọc ngoài cùng bên trái của 1 bức ảnh
-grid-column-end:line của col kết thúc VD:3 thì sẽ là line dọc ngoài cùng bên phải của bức ảnh thứ 2,còn line t2 sẽ là line ngoài cùng bên trái của bức ảnh t2
hoặc viết ngắn: grid-column:[start num]/[end num] *nếu để end là -1 thì sẽ scretch và không cho content vào nằm cạnh
*có thể Cố định số col/row: grid-column(grid-row):span [number]
-căn chỉnh grid riêng lẻ: justify-self(điều chỉnh item theo axis theo row)
align-self(điều chỉnh item theo axis theo col)
*Cách bỏ khoảng trống trên trình duyệt:
body{
margin:auto 0;
}
Để item riêng lẻ có thể ở trái cùng hoặc phải cùng có thể dùng margin-left:auto(phải cùng) và ngược lại
*Để box không tự động xuống dòng chữ khi thu nhỏ màn hình lại ta có thể dùng media-query và để media query hoạt động ta cần
<meta name="viewport" content="width=device-width, initial-scale=1.0">
và chú ý thứ tự đặt media query sau những nơi cần thay đổi
VD:@media only screen and(max-width(<=size sẽ trigger)/min-width(>size sẽ trigger):[size]){
//CSS sẽ thay đổi khi viewport trigger
}
*Khi center content của flex ở giữa nếu sử dụng height là px(fix cứng)-> sẽ không responsive-> sử dụng vh(view height=tỷ lệ % chiều cao của container đó so với khung màn hình hiện tại vd 100vh=100%)
Để làm sticky content: {
position:fixed;
top:0;
width:100%;
}
-Bootstrap:
CDN:content delivery network
Để style đè lên style của bootstap đơn giản chỉ cần để <link> phía dưới link của boostrap
Grid:căn chỉnh theo 12 cột
<div class="container">
<div class="row [attibute vd:justify-cotent-center]">
<div class="col col-sm-[1->12]">
...
*.col-:None(auto) xs:extra small sm(540px):small md(720px):medium lg(960px):large xl(1140px):extra large
*Sử dụng cái nào thì các size về sau sẽ đổi(nếu không set). VD medium-> large, extra large
*offset: dời sang phải bao nhiêu ô
VD:class="col-md-offset-3" dời vào 3 ô khi màn hình medium
*Cách tạo 1 navbar trong bootstrap:
-bỏ vào <nav class="navbar "> (Các thuộc tính khác như navbar-dark:chữ trong theme tối, bg-light/dark/primary:màu nav(có thể tự chỉnh bằng background color))
*thêm navbar-expand-[sm/md/lg...]:từ đâu thì hiện full thay vì 3/ menu(toggle button)
-phần header(icon,tên page) bỏ vào tag <a class="navbar-brand">
-<button class="navbar-toggler" data-toggle="collapse" data-target="#navbarMenu"><span class="navbar-toggler-icon"></button>:thêm icon 3/.
+data-toggle: lắng nghe thay đổi khi thay đổi responsive.
+data-target:Nơi nào sẽ dc đưa vào icon(recommend đưa vào id)
-<div class="collapse navbar-collapse" id="navbarMenu">: để responsive(từ đâu thì sẽ hiện full item thay vì 3/ menu), id để giúp data-target xác định nơi sẽ lấy bỏ vào icon menu
-các mục khác bỏ trong <ul class="navbar-nav mr-auto" >: mr-auto để canh item qua trái(thêm margin bên phải). K dùng mr/mx/ml-auto ở đây nếu có toggle
+class="navbar-nav mr/mx/ml-auto":giữ menu item và canh chỉnh margin khi có toggle
-<li class="nav-item"> chứa <a href="#" class="nav-link">
*có 2 lí do button k hoạt động:
+add gì đó vào button để hoạt động:data-toggle
+JS pack từ bootstrap
*navbar-nav -> nav-item -> nav-link
Để content nằm giữa, ta bao chúng trong tag <header> hoặc <section> rồi dùng class="text-center" và để customize theo full màn hình ... ta dùng col-[number] để căn chỉnh
Để vertical align:ta k dùng class của bootstrap vì dùng inline... ->FLEX
*Kích hoạt flex: class="d-flex"
-vertical align (class="align-items-center") căn giữa theo chiều dọc
*khi dùng vertical align ta chú ý xem content ta đang dc bao full màn hình hay không, nếu không thì dùng class="h-100" để full màn hình theo chiều dọc
*Muốn cho item trong toggler dc căn chỉnh ta dùng text-center/text-right/text-left
ANIMATE.CSS https://daneden.github.io/animate.css/ dùng class như bootstrap để sử dụng
*CÁCH ĐỂ HOST BẰNG GITHUB:
Setting->Github pages->source:master branch->refresh->sau đó lấy link tại chỗ đó vào bỏ vào mô ta để thuận tiện
Với project react: tạo "homepage":"[link-user-git]/[project]" trong package.json-> npm install --save gh-pages-> thêm 2 line vào "scripts"-> npm run deploy(và phải run redeploy trước)-> setting -> github pages -> đổi source master branch thành gh-pages branch
JAVASCRIPT:
-action của browser
-<script type="text/javascript" src="script.js"></script> đặt trên </body>. *Có thể có nhiều script
-Để ghi ký tự ta dùng "\"
-"o" > "e" do o đứng sau e hay lớn hơn trong bảng chữ cái
-convert to number: Number([string])
-Nhập từ prompt: prompt() và func trả về string
+function newFunction(){}//function declaration
+var newFunction=function nameFunction(){}; or var newFunction=function(){};//function expression
*expression: những thứ sẽ có giá trị trả về
Sử dụng arrow function để tránh việc trùng lặp hàm vs biến gây bug
*Arrow function k thể dùng để tạo constructor function
VD:const greet = ()=>{}
*Closure
VD:
const first = () =>{
const greet ='Hi';
const second = () =>{alert(greet);}
return second;
}
const newFunc=first();
newFunc();
Khi chạy first() chỉ có sencond() dc chạy nhưng greet k ở trong scope của second. "Child scope luôn dc access vào parent scope"
Ngay cả khi first() k chạy. web browser sẽ nhớ greet
-> The function only run once. BUT it's trying to remember that there are references to those variable so the child scope always has access to the parent scope, nhưng ngược lại parent k thể vs child
*Currying: tạo function lấy 1 arg at a time, để có thể thêm arg khác tại lúc khác
VD: const multiply =(a,b)=>a*b;
const curriedMultiply = (a) =>(b)=>a*b; VD: curriedMultiply(4)(3);
const multiplyBy5=curriedMultiply(5); VD:multiplyBy5(4)....
*compose:adding 2 function together to form a 3rd function where the output of 1 function is the input of the other
VD: const compose(f,g)=>(a)=>f(g(a));
const sum = (num) => num+1;
compose(sum,sum)(5);
*Avoiding Side Effects, functional purity
var a=1;
function b(){a=2;}
->Side effect: affect outside
functional purity: luôn return value và k có side effect -> Deterministic: bất kể input nào từ function luôn trả về giá trị
*Two elements of a pure function:
1. Deterministic --> always produces the same results given the same inputs
2. No Side Effects --> It does not depend on any state, or data, change during a program’s execution. It must only depend on its input elements.
*array.filter: Trả về giá trị cho mảng mới nếu đúng và bỏ qua nếu sai
*array.reduce([biến tạm],[phần tử])=>{},[giá trị của biến tạm])
*Type coercion: VD:1=='1'
*IIFE: Thực thi hàm ngay lập tức VD: (myFunc(){}) . Chú ý phải có dấu ";" ở trước, khi dùng cách này thì bất cứ gì trong "()" thì sẽ k bị ảnh hưởng ở bên ngoài (private trong OOP)
-Callback function khi thỏa
+ Là hàm
+ Dc truyền qua đối số
+Dc gọi lại (trong hàm nhận đối số)
VD:function myFunc(param){
param()
}
function myCallback(param){
...
}
myFunc(myCallback)
*Các function trong .map,.filter,.... hiển nhiên dc gọi lại-> cũng là callback
-StopPropagation:
VD: <div onClick={()=>{}}>
<button onClick ={()=>{}}>btn</button>
</div>
Khi ta nhấn vào thằng con thì 2 Dom event sẽ cùng hoạt động (sẽ lan dần ra các element ông, cha). Để tránh điều này ta sửa dụng e.StopPropagarion trong function con (e là mouse event).
-DOM event: onClick,....
-event listener: .addEventListener([event],[function]), .removeEventListener([event],[function]) chính vì thế khi dùng event listener ta nên tách function ra rồi gọi đến
VD:btn.removeEventListener('click',viec1)
OBJECT
-reference type = non-primitive type: chỉ dc tạo bởi programmer, k phải type define sẵn(primitive type)
*Để copy reference type:
+Với array: newArr.concat(arr)
+Với object:clone = Object.assign({},[source object])
hoặc spread operator: {...obj}
*VD:obj={a:'a',b:'b',c:{deep:'...'}}
let clone=Object.assign({},obj);
let clone2={...obj}
obj.c.deep='hahaha';
->Vẫn sẽ đổi vì ta chỉ thực hiện shallow copy,clone first level(clone mem.address)
*Để deep clone: dùng JSON, chuyển thành string và chuyển trở lại nhưng có thể long time nếu obj "lớn"->performance
VD:let superClone=JSON.parse(JSON.stringify(obj))
-context khác scope. context tell where we are in the object(this)
-instantiation:khi tạo copy của object và reuse code(dùng class,extends..)
*mỗi lần extends phải gọi constructor của function cha = super(//prop muốn dc dùng từ constructor của cha) và super() sẽ chạy đến constructor của cha + để sử dụng dc "this" từ con(Attach this khi gọi super sẽ gán 'this' là class extend từ cha vào constructor của cha)
VD: class Player(){
constructor(name,type){//Thứ đầu tiên dc tạo (properties)
this.name=name;
this.type=type;
}
introduce();
}
VD2: class Wizard extends Player{
constructor(name,type)
{
super(name,type)
}
}
*ES7
-[string/array].includes('[..]')->true/false
-** -> mũ
*ES8
-[string].padStart([number])/padEnd([number): thêm space từ đầu đến chữ/từ chữ đến cuối
-trailing commas in function parameter lists and calls
VD:
const fun=((a,b,c,d,)=>{console.log(a);})
fun(1,2,3,4,)
-Object k cho phép filter,reduce,... ->Object.keys(obj) để có thể dùng như array
VD:Object.keys(obj).forEach((key,index)=>{console.log(key,obj[key]})
-Object.values/Object.entries:
Với Object.values(..) tương tự .keys(..) ta lập tức lấy dc value của key trong object
Với Object.entries(..) tương tự .keys(..) ta lập tức lấy dc ["key","value"]
VD:
let obj = {
my: 'name',
is: 'Rudolf',
the: 'raindeer'
}
// to this:
'my name is Rudolf the raindeer'
Object.entries(obj).map(value => value.join(" ")).join(' ')
-Async/Await
*ES10
-flat([number]): default là 1. Bao nhiêu lần muốn flat array(có thể flat ',' '[]'). Nếu number >= số "[]" thì cũng sẽ flat hết
VD:const array=[1,[2,3],[4,5]]
array.flat()
->[1,2,3,4,5]
-flatMap():
VD: jN=j.flatMap(creature=> creature+'a'); -> a sẽ dc đưa kế bên cạng phần tử của các phần tử trong array khi bỏ nest, nếu là phần tử nest thì nằm bên cạnh phần tử cuối
-trimStart()/trimEnd():xóa space đầu /cuối
-fromEntries:ngược lại của entries
VD: userProfiles=[['a',23],['b',23]]
Object.fromEntries(userProfiles)
->{a:23,b:40}
-try/catch
*for..of:interating(lặp đi lặp lại) array/string, k thể dùng for of cho Object
*for..in:enumerating(liệt kê) object-properties, nếu dùng for in cho array ta lấy dc index
*debugger;:khi chạy tới dey-> dừng tại đây
-hasOwnProperty() để ktra thuộc tính đó có phải thuộc tính của obj đó k mà k kế thừa từ prototype.
Vd: array có prototype là .check khi kiểm tra qua tất cả index thì chỉ có 0,1,... Chứ k bao gồm check khi thực hiện for/in
WEBSOCKET(socket.io)
-allow real time communication từ browser ->server cũng như bất cứ ai connect tới server đó
-real-time websocket communication
VD:
----SERVER----
const io=require('socket.io')([port])
io.on('connection',socket=>{//mỗi lần user load website sẽ gọi function này và sẽ đưa mỗi user 1 socket. Với socket này ta có thể send mess tới ng dùng
socket.emit('[eventName]',data)
socket.on('send-chat-message',message=>{//handling event
socket.broadcast.emit('chat-message',message)//send mess lại cho all client connect tới nó ngoại trừ ng đã gửi
}
})
----CLIENT----
const socket=io('[location hosting socket vd:http://localhost:3000]')//get socket variable
const messageContainer = document.getElementById('message-container');
const messageForm = document.getElementById('send-container');
const messageInput = document.getElementById('message-input');
socket.on('[eventName]',data=>{//data dc gửi từ server
appendMessage(data)
})
messageForm.addEventListener('submit',e=>{
e.preventDefault()//stop posting to server which reload page(nếu k dùng sẽ lose all message khi submit)
const message = messageInput.value
socket.emit('send-chat-message',message)
messageInput.value=''//clear input text
})
function appendMessage(message){
const messageElement = document.createElement('div')
messageElement.innerText=message
messageContainer.append(messageElement)
}
---HTML của client----
*defer:When present, it specifies that the script is executed when the page has finished parsing
<script defer src="http://localhost:3000/socket.io/socket.io.js"></script>//nơi socketIO working JS file include io function
<script defer src="script.js"></script>
DOM:tạo ra để thay đổi HTML,CSS
->change all the HTML element in the page
->change all the HTML attributes in the page
->change all the CSS styles in the page
->Remove existing HTML elements and attributes
->add new HTML elements and attributes
->Javascript can react to all existing HTML events in the page
->Javascript can create new HTML events in the page
-document object thuộc window object
-DOM quyết định cái gì sẽ dc render(HTML,CSS) và JS sẽ qua JS engine của trình duyệt để thay đổi trên DOM
-querySelector trả về item đầu tiên mà nó tìm thấy. VD:document.querySelector(".color1");
-querySelectorAll trả về item tất cả item mà nó tìm thấy. VD: document.querySelectorAll("[tag1]","[tag2]",..)
-lấy attribute của tag(id,class,...) :document.[querySelector(["tag name/id/class..."])].getAttribute("[tên attribute cần lấy giá trị]")
-set attribute của tag: document.[querySelector(["tag name/id/class..."])].setAttribute("key","value")
*Thay đổi styles: document.querySelector("h1").style."background"="yellow" hoặc body.style.background="linear-gradient(to right,"+color1.value+","+color2.value+")";
*muốn dùng style tách rời từ file CSS:
document.querySelector("[tag]").className = "[tên class dc style từ file CSS]"
*Kiểm tra(lấy) class của element:
document.querySelector("[tag]").classList;
+Thêm class: document.querySelector("[tag]").classList.add("[class]")
+Remove classs: document.querySelector("[tag]").classList.remove("[class]")
+Tắt/bật class: document.querySelector("[tag]").classList.toogle("[class]")
Ngoài ra thay đổi element: document.querySelector("[tag]").innerHTML="[tag syntax VD:"<strong>...</strong>"]"
*Kiểm tra parent/children: VD:document.querySelector("li")[1].parentElement;
*Lưu querySelector trong biến là Quan trọng vì khi ta dùng lại cú pháp đó lần nữa browser k cần phải loopkup từ DOM xuống element...
-Event:click,hover,...
*Event "input" sẽ lắng nghe sự thay đổi của giá trị
VD: var button=document.getElementsByTagName("button")->trả về array
*lắng nghe event: [reference tới element].addEventListener([event],[function sẽ chạy->dc exec mỗi lần có event, không phải function dc execute(không để dấu"()")])
VD:color1.addEventListener("input",setGradient) hoặc <input oninput="setGradient()" ...>
//Khác biệt ở chỗ sử dụng on... chỉ 1 attribute trong khi addEventListener có thể add nhiều function/event
VD: button[0].addEventListener("click",function(){console.log("click");})
+Tạo element mới(nhưng không có nội dung): document.createElement("[tag]");
+Thêm nội dung vào tag/thêm child: document.createElement("[tag]").appendChild(document.createTextNode("[...]"))
VD: ul.appendChild(li);
+Có thể lấy giá trị vd: input.value
*input.addEventListener("keypress",function(event){console.log(event.keyCode == 13)})//Kiểm tra keyCode có là "enter" hay không
*Color picker: <input type="color">
Thêm text: VD:css.textContent=body.style.background+";";
*Có nhiều method trong DOM: VD: createTextNode/textContent/innerHTML -> check vs browser để ktra có dc hỗ trợ/ lúc trc chỉ 1 số browser hỗ trợ querySelector ->jquery
JQuery: add thêm vào JS(properties,functions,..)->quản lý dễ dàng, thích hợp vs browser nhưng imperative(phải nói làm gì từng dòng một->dependent nhiều)
*innerHTML -> mỗi lần innerHTML set->HTML phải dán vào, DOM phải construct và đưa vào document(re-create lại)/cross-site scripting(XSS)
minimize DOM malnipulation+events->React
Babel->tạo ra để dùng JS features mới theo ECMA mới
ES6
Destructuring:{[prop muốn lấy từ object],..}=[object muốn lấy]
VD: var obj={
a:'1',
b: {
c:2
}
}
Khi dùng destructuring:
+var {a,b:{c}} = obj : Khi ta muốn lấy a và c của object b rồi lưu vào biến cùng tên
+var {a,b:{c:d}} = obj : Khi ta muốn lấy a và c của object b rồi lưu vào biến cùng tên, đồng thời đổi tên c thành d
+var {a,b:{d = 0}} = obj : Khi ta muốn lấy a và d của object b rồi lưu vào biến cùng tên, đồng thời gán mặc định giá trị khi không có
Dynamic prop: ["tên"]:value
Nếu prop và value same VD: obj={a:a,b:b} ->obj={a,b}
function default value: function greet(name="",age=30,pet="cat"){}
string: `${expression}`
Trong trường hợp dùng Nullish coalescing operator (??) nó kiểm tra khi vế trái là null hoặc undefined.Trong trường hợp dùng or (||) thì nó kiểm tra rồi trả vế phải bếu có falsy vế trái
VD:const [jobs,setJobs]=useState(storageJobs ?? [])
const [jobs1,setJobs1]=useState(storageJobs1 || [])
*Để deep copy array/object ta dùng spread operator hoặc Object.assign. Nếu Object/array lồng nhau, ta dùng JSON stringtify r parse
VD:const a = {
languages: {
vi: 'Xin chào'
}
}
let b = JSON.parse(JSON.stringify(a))
b.languages.vi = 'Chao xìn'
console.log(b.languages.vi) // Chao xìn
console.log(a.languages.vi) // Xin chào
JAVASCRIPT RUNTIME ENVIRONMENT
+JS Engine:
-Memory Heap:memory allocate(VD: global variable, nếu nhiều và unused vì heap có giới hạn->memory leak
-Call stack: (First in last out)code read and execute. Recursion có thể gây stackoverflow
-JS:single-thread->non-blocking:vẫn chạy khi có tác vụ đang xử lý
Other language có thể có multi-thread->có thể Deadlock
*Synchronous: Cái sau chỉ có thể chạy khi cái trc nó xong
*Asynchronous: Dùng khi có tác vụ dài(non-blocking)
+Web APIs(DOM(document),AJAX(XMLHttpRequest),Timeout(setTimeout))
+Callback Queue(onClick,onLoad,onDone)
*Event loop
MODULES(low to high)
-Inline Script: bỏ code trong tag script r viết tring HTML file. Nếu file lớn? k reuse dc, muốn dùng phải copy, pollution global namespace(tên dẽ trùng lặp)
-Script tags: vd như các file JS của bootstrap(Nhiều file JS).Nếu thêm page mới-> vẫn phải copy + Lack of dependency resolution(nếu file 1 access function từ file 4->fail vì chưa load)
-IIFE(immediatly invoke function execution):
VD:
//js1 first file loaded
var myApp={}
//js2
(function(){
myApp.add = function(a,b){return a+b;}
})();
wrap function trong "()" JS đọc và evaluate và kết thúc vs "()" để run function, có scope riêng. Nếu muốn add vào myApp, add vào properties/method->reduce global namespace về 1. Order vẫn quan trọng và khi có nhiều scripts ta phải thêm vào đúng chỗ vì file đó maybe dependence file khác load trc nó
-browserify:commonJS allow using certain syntax, Browserify sẽ dùng commonJS syntax này ->module bundler(read qua tất cả file/syntax và bỏ tất cả trong 1 file)(bundle.js) và file này sẽ dc view bởi user(0 phải dev,dev thì work trên seperate file run through browserify)
VD:
//js1
module.exports=funtion add(a,b){return a+b;}
//js2
var add=require('./add');
-ES6+webpack2(như bundler + có thể dùng ES6 all browser):
VD:
//js1
export const add =(a,b)=>a+b; ->export dc nhiều
export default funtion add(){
return a+b; ->export dc 1
}
//js2
import {add}from './add'; //destructring vs export
//or
import add from './add'; //với export default
NPM
-dc tạo dành cho node cho phép require syntax(nhưng k cho browser)->browerify allow to use syntax on browser->bundle
Tạo ra để có thể share JS code. 3 loại pack
+use on browser(front end) download jQuery from NPM
+dùng command line để add pack
+NPM package
-npm init
-khi máy khác dùng project có pack npm: npm install
-con số bên cạnh pack: [mature release][feature][version tăng 1 khi sửa lỗi,bug]
*dev dependecies:package cho development,testing: npm i --save-dev ....->chạy bằng: npm run [tên đã đặt ở "script" khi sửa "test":... = "...":"..."]
-k cần browserify để bundle(mà dùng lệnh npm run...) mỗi lần:trong file package.json sửa test->build(hoặc tên khác) và value là "browserify script.js > bundle.js [&& live-server](nếu muốn dùng thêm live-server)"
*dùng require đối vs browserify+thay vì dùng index.html bên HTML file ta dùng file bundle để chạy.Khi thay đổi ta cần phải chạy lại lệnh "browserify..."
->chạy: npm run build(hoặc tên khác) trên terminal
*Sử dụng tachyons <=> bootstrap: sử dụng class để styles
REACT
-Nếu chưa có react: npm install -g create-react-app
-init: create-react-app [name] hoặc npx create-react-app [tên app]
-"scripts" tất cả dc dùng bởi "react-scripts" trong package.json dùng để auto bundle mà k cần dùng browserify
->dùng import thay cho require on top
-import React from 'react': view library
-import ReactDOM from 'react-dom' :dùng cho DOM website
-react cho phép dùng css k chỉ 1 file VD: import './index.css'
-package-lock.json:lock version dependecies khi qua end-point khác
*Để update:update "react-scripts","react".... thành ver khác và chạy npm install
*vs config product: npm run eject:dùng khi end up customize script và tự customize
-npm start: chạy app
-<iv id ="root"></div>:react sẽ chạy ở đây
-render() method return JSX(javascript XML)
*JSX -babel-> javascript
-class extend từ Component phải render(){return()} gì đó
-component phải dc viết hoa chữ đầu VD: Hello.js
*Có thể sử dụng .jsx để better impletion
-ta import {Component} là destructring <=> React.Component
-css dc import vào component
-index.js: entry point của app(main script)
-import obj từ module(import React from 'react'/import ReactDOM from 'react-dom'
-cách React tạo ra element: const element =<hi>Hello World</h1>//babel sẽ compile React.createElement([element],[prop(className,src...)],[child(text hay element khác)]++)
-Trong cấu trúc tree, khi 1 node thay đổi chỉ có các node phía dưới nó thay đổi
*VirtualDOM dùng JSX và dùng nó để tạo thay đổi lên DOM thật
*Virtual DOM(plaint JS object):state thay đổi-> get element mới và compare vs cái trc đó và xem thay đổi ->update tới DOM
-ReactDOM.render([element muốn render/app(root) component],[render ở đâu])
vd:ReactDOM.render(element,document.getElementById("root"))
*Thay vì dùng class như HTML ta dùng className
*props của 1 component dc đặt trong {[expression]}
*props không bao giờ thay đổi, static
*state: object mô ta application, có thể thay đổi, dynamic
khi dùng: parent feed state to child component,as soon as child component receive state -> become prop
VD:<Hello greeting={''}/> và thay đổi trong component nội dung JSX thay đổi thành <...>{this.props.greeting}<.../>
*Khi sử dụng props khi bên class ta dùng this còn bên function thì không
const Hello = (props)=>{ class Hello extends React.Component{
return(...this.props.greeting...); <=> render(){return(...props.greeting....);}
} }
*Khi sử dụng function vẫn phải import React vì dùng jsx
*Return duy nhất 1 JSX, k thể return nhiều element trong (), nếu muốn return nhiều phải đặt tất cả trong <div>
*Nếu là <div> nhưng không làm gì ngoài việc bao tất cả ta có thể thay bằng React.Fragment hoặc bỏ trong empty element(hay còn dc gọi là fragment) <></>
*class khi sử dụng trong react là className
*Ta có thể destrucring từ props VD:const Card = props =>{const {name,email,id}=props}
*Ta có thể destructring ngay trong function VD:const Card = ({name,email,id})=>{})
-Khi truyền prop từ array ta thực hiện func map() để trả về jsx VD: return <Card id={robot.id} name={robot.name} email={robots.email}/>
và gọi biến chứa nó ở return trong render dưới dạng expression(đặt trong {})
->Với điều này React sẽ đưa ra warning nó cần 1 key vì khi ta xóa 1 component nó không biết cái nào là cái nào dẫn tới render toàn bộ vì vậy ta có thể cho key={index}
-Để 2 component có thể tương tác được với nhau(như searchBar và View, khi tìm kiếm->view đổi) -> có thể dùng STATE/setState({//object})
*Để dùng state phải dùng class thay cho function và phải khai báo constructor() vào để this.state bên trong constructor và sau super() để có thể xài this
*Để dùng state cho mà không cần tạo class (function only) ta dùng {useState} from 'react' và khi sử dụng ta gọi useState(//default state(array))
*Để ktra input nhập vào: (e)=>{console.log(e.target.value)}
*Khi sử dụng this, ta xem xét nơi nó xảy ra(có thể là 1 component con) để tránh lỗi. Ta có thể dùng arrow function hoặc bind(//obj để làm this)(method dành cho function) để thay đổi context
*Lifecycle: những method sẽ dc gọi trong quá trình app hoạt động
-Mount:Khi ta refresh hay access app thì app sẽ dc mount vào root
->Khi 2 DOM chạy song song, virtualDOM tạo ra trước sau đó dùng DomAPI(từ 'react-dom') tính toán để ra element cần thiết hiển thị lên trình duyệt. Lúc gọi API để thêm component vào trong trang
-Update:khi thay đổi state(re-render)
-Unmount: component k dùng nữa, mất đi
-ComponentDidMount():dc gọi DUY NHẤT 1 lần khi component dc khởi tạo và gán vào DOM. Nên gọi API ở đây
-ComponentDidUpdate(): dc gọi sau khi render() dc gọi hay setState làm re-render
-ComponentWillUnmount():dc gọi trc khi unmount. Có thể dùng remove listener,setTimeout,setInterval ở componentDidmount tránh memory leak-tồn tại mãi trong memory mà k dc gỡ ra(vd socket event listener)
*Web chạy(Mounted): constructor->componentWillMount->render->componentDidMount
*Khi update(setState):componentWillReceiveProps->shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate
*Thay đổi page(Unmounted):componentWillUnmount()
Sau khi thay đổi state: component render-> componentDidUpdate
Khi ta đổi state của cha(App): app render->component render->componentDidUpdate->App update
Khi setState để ẩn component: app render->componentWillUnmount->App update
*setState là async, và khi dùng sẽ trigger re-render(update)
*để component con k render thì trong nó thêm shouldComponentUpdate(nextProps,nextState)(có thể overwrite): mặc định là true, nếu return false thì nó sẽ k render
App render->App update
VD: //Tối ưu, cần update nhánh nào thì update, k cần render lại all
shouldComponentUpdate(nextProps,nextState){
if(this.state.count === nextState.count){
return false;
}
return true;
}
*Khi style component ta có thể style thành 1 file chung rồi import qua index.js hoặc tạo file css riêng cho component
*Thông thường, không enter user trong APP mà quản lý qua API
*fetch() thuộc window object: make req to server
*Để tạo 1 wrap component(khác với self-closing component)
*childen: là component bên trong wrap component. Dùng children để render bên trong wrap-component, mọi obj props trong component đều có children(props.children). Với props.children ta có thể tạo component wrap component khác(vd để có thể scrollable...)
VD: component Scroll bao ngoài component Card.
const Scroll=(props)=>{
return (<div style={{overflowY:'scroll',height:'500px'}}>{props.children}</div>)
}
*Để organize folder structure:src->components(chú ý bỏ chung file font của file css nếu có)/containers(smart component: những component có state,class chú ý bỏ chung file font của file css nếu có)
*Sau khi hoàn thành: npm run build -> khi chạy: tạo folder build dc optimize
Khi update: ta có thể sửa version trong package.json rồi npm install
npm update:kiểm tra upgrade("^" nghĩa là có) và upgrade đảm bảo k breaking change, ta có thể sửa lại thành ">" để update
npm audit: đưa issue là gì
npm audit fix [--force(bắt buộc)]: update/sửa lỗi khi có vulnerable
-Error boundaries: nếu có lỗi ở 1 component -> đưa giải pháp. Nhưng chỉ có production(user) mới thấy dc, còn trong dev mode vẫn hiện lỗi
*componentDidCatch(error,info):Như try catch block,
VD: ta tạo 1 class ErrorBoundry là 1 wrapper component
class ErrorBoundry extends Component{
constructor(props){
super(props)
this.state={hasError:false}
}
componentDidCatch(error,info){
this.setState({hasError:true})
}
render(){
if(this.state.hasError){
return <h1>Something wrong</h1>
}
return this.props.children
}
}
REDUX
->Good for managing large state(React app trở nên lớn,phức tạp)
->Useful for sharing data between containers
->Predictable state management using 3 principles
+>Single source of truth: 1 single big obj describe toàn bộ state
+>State is read only: ngăn modified và tránh lỗi k mong muốn. Thay vào đó ta tạo new state sau mỗi action
+>Changes using pure functions(nhận input và trả output có thể predict)
Action -Middleware->Reducer->Store -React->make change
-Action: user does như clicking button, drop down menu...
-Reducer: Sau khi thực hiện action. Là 1 pure function receive input là action mà user trigger và output là state hay store
-Store: enire state of the app, React sẽ thấy sự thay đổi và update view layer
*Flux pattern: Action->Dispatcher->store->View
*MVC pattern:Action->Controller->Model(s)->View(s):User click và theo hướng controller -> update model(data có thể là state)-> update view
-state descript what our app look like
-Nếu có thay đổi ta update component và render(through an event)-> project càng lớn càng khó keep track state
VD: //App.js
onSearchChange=(event)=>{
this.setState({...})
}
...
render(){...
<SearchBox searchChange={this.onSearchChange}/>
..}
//Card.js
const SearchBox=({searchChange})=>{
return (
<div className="pa2">
<input
onChange={searchChange}
type="search" placeholder='Search robots'/>
</div>
);
}
-Redux === this.state + React. Vẫn có thể dùng this.state song song Redux trong component vì Redux k thay thế hoàn toàn
-Install Redux: npm install redux
-npm install react-redux : nói react sử dụng redux -> connect only container(App.js) Redux store(Obj lớn lưu trữ state cho toàn app),container sẽ communicate với store, những component khác container sẽ không biết redux exist
-ACTION:
//tạo file actions.js
import {CHANGE_SEARCHFIELD} from './constant.js'
export const [biến] = ([tham biến])=>({
type:[tên action(viết hoa hoàn toàn(string) hoặc ta có thể import từ file constant)]',
payload:[tham biến] ->data cần dc tới reducer
})
//constants.js
export const CHANGE_SEARCHFIELD='CHANGE_SEARCHFIELD'
-REDUCER:đọc actions và lấy state
//reducer.js
const intialState={
searchField:''
}
export const searchRobots =(state=intialState,action={}){
switch(action.type){
case: CHANGE_SEARCH_FIELD:
return Object.assign({},state, {searchField:action.payload}//(obj)thứ muốn change)//new state
//hoặc return{...state, {searchField:action.payload}}//object spread operator
default:
return state;
}
}
-Connect với app:
//index.js(root)
import {Provider} from 'react-redux'
import {[tên reducer]} from '[path]'
-STORE:
//index.js(root)
import {createStore} from 'redux'
Tạo store: const store=createStore([tên reducer])//sẽ có nhiều reducer->complex->combine all reducer thành rootReducer
ReactDOM.render=createStore(<App store={store}/>,document...)
->lúc này store có thể access và pass down vào App. Ta có thể ktra bằng cách thử log this.props.store trong componentDidMount ở App. Ta có dc method:dispatch,getState,replaceReducer,subcribe,Symbol(observable)... Ktra bằng this.props.store.getState()
Cách pass store vào trên sẽ buộc ta pass store all the way down component Tree tới smaller component(tất cả component phải có prop store <...store={store}/>) -> sử dụng Provider của react-redux: wrap <Provider></Provider> là 1 wrap component xung quanh App và replace store ở App lên Provider: <Provider store={store}><App/></Provider> kết hợp connect để finish connection
-CONNECT: connect function giúp avoid store.subcribe(subcribe any component that that is interested to be aware of redux and listen to any changes) -> simplified với connect()
Muốn component nhận biết thay đổi và subcribe nó(thường ta gọi ở container)
+Ở component muốn kết nối redux:
import {[action]} from '[path]'
VD: import {setSearchField} from '../actions'
import {connect} from 'react-redux'
và ở cuối file: export default connect(mapStateToProps//state muốn nghe,mapDispatchToProps//action muốn nghe)([component])
Tạo 2 function:
+const mapStateToProps=state=>{
return {
[tên prop component muốn]:state.[reducer].[prop của state trong reducer]
}
}
->State nào sẽ dc lắng nghe và send down as prop, prop dùng sẽ dc nhận từ state reducer trả về.
*nếu store chỉ có 1 reducer(k phải root) thì ta có thể sủ dụng state.searchField thay vì state.searchRobots.searchField
VD:const mapStateToProps=state=>{
return {
searchfield:state.searchRobots.searchfield
}
}
+const mapDispatchToProps=(dispatch)//dispatch: what trigger action(thứ sẽ send action đi)
{
return [tên prop sẽ nhận]:([biến])=>dispatch([action([biến/prop của biến]...)])
}
->props nào sẽ dc lắng nghe đó là action cần dispatch
VD:
const mapDispatchToProps=(dispatch)
{
return {onSearchChange:(event)=>dispatch(setSearchField(event.target.value)))}
}
Và khi sử dụng, state dc nhận sẽ truyền xuống prop.
VD: const {searchfield,onSearchChange}=this.props
-MIDDLEWARE:lắng nghe action và là 1 tunnel mà action đi qua(giúp modify action hay trigger action khác)
+npm install redux-logger:middleware này giúp logging in console giúp debug dễ dàng mà k cần console.log
const logger=createLogger()->logger function which is middleware, có thể apply cho redux app
Apply middleware cho redux: import {applyMiddleware} from 'redux' và thêm vào
const store=createStore(searchRobots,applyMiddleware([tên của middleware ta muốn thêm],...))
*Không thể sử dụng async với action vì khi lấy API reducer sẽ ktra action và k thấy payload vì thế nó k make change. Để tạo action là async và theo flux để make change:
Sử dụng redux-thunk:middleware provide get state và dispatch function chúng ta có thể passed on.Ta có thể handle side effect(như AJAX call)
Redux-thunk:middleware chờ và xem có action nào trả về function thay vì object để xử lý
import thunkMiddleware from 'redux-thunk'
VD://index.js(root)
const store=createStore(searchRobots,applyMiddleware)
*Vì là promise nên sẽ có 3 state của action: PENDING(lần đầu send request, sẽ pending để chờ promise return),SUCCESS,FAILED->standard with all async actions như AJAX calls
Đối với action của async:
export const [tên func] = ()=> (dispatch){
//function
dispatch({type:[PENDING]})
fetch('[API]').then(res=>res.json())
.then(data=>dispatch({type:[SUCCESS],payload:data}))
.catch(err=>dispatch({type:[FAILED],payload:err}))
}
Với reducer của async: ta cũng tạo 3 case tương ứng
VD:
export const requestRobots=(state=initialState,action={})=>{
switch(action.type){
case REQUEST_ROBOTS_PENDING:
return Object.assign({},state,{isPending:true})
case REQUEST_ROBOTS_SUCCESS:
return Object.assign({},state,{robots:action.payload,isPending:false})
case REQUEST_ROBOTS_FAILED:
return Object.assign({},state,{error:action.payload,isPending:false})
default:
return state;
}
}
*Nếu reducer không liên quan đến state của nhau thì nên tạo initialState khác nhau để tránh đụng độ. Và với nhiều reducer muốn dùng cùng nhau:
import {combineRuducers} from 'redux'
const rootReducer=combineRuducers({[reducer 1],[reducer 2],...})
const store=createStore(rootReducer)
*Sau khi dùng combineReducer, nếu đang sử dụng mapStateToProps với dạng state.prop chuyển thành state.[reducer chứa prop].prop
*Với mapDispatchToProps vớ async action: ta trả về function(function của async action ở actions.js) thay vì dispatch(object)
VD:const mapDispatchToProps=(dispatch)=>{
return{
onRequestRobots:()=>dispatch(requestRobots())
}
}
*Cách thực hiện: constants.js(Tạo file riêng cho từng action và export)->actions.js(import từ constants và tạo action là function trả về một plain javascript object(PJO))->reducers.js(tạo initalState vào tạo function với state=initialState,action={} bên trong switch action.type để trả về các object chứa các state mong muốn->Ở root import store và Provider bao App->ở component con dùng connect,mapStateToProps(state),mapDispatchToProps(dispatch)
*Complex + more async action -> REDUX SAGA
*HTML sẽ k làm dc gì nhiều nếu k thể fetch document from around the world and different computer -> HTTP(hyper text transfer protocol) cho phép fetching resources như HTML,...
*Client và server có thể communicate by exchangining invidual(cá nhân) messages. The messages send by client(web browser) gọi là request và message dc gửi bởi server gọi là response
Có thể xem HTTP là language dc sử dụng bởi client và server.
Với GET POST PUT DELETE để make request ở client side
*HTTP dùng để fetch part of documents to update web pages on demand which is call AJAX
Với server send ta 2 main things: HTTP status code(200 OK,404 not found,..) và data như HTML...
+Như sử dụng GET request ở form ta gửi thông tin nhưng lại hiện lên URL thông tin ta nhập vào(query string) và form data(Khi Inscpect network)
+Với POST ta gửi thông tin, có thông tin ở form data nhưng không có query string ở URL và có thêm application/x-www-form-urlencoded để nói đây là form với form data là body và k display lên URL
-> có thể send data qua query string hoặc body
*HTTPS:HTTP secure dc dùng transport layer security(TLS) hoặc predessor secure socket layer(SSL)
JSON
Với HTTP ta k thể post dc mọi thứ, khi trao đổi giữa browser va client chỉ có thể là text, mặc khác khi ta gửi JS object tới server có thể dùng language(Python,Go,PHP,...) -> k hiểu
Text có thể dc hiểu bởi tất cả:
->JSON:
+syntax for storing and exchanging data. (k phải duy nhất, có thể là XML) Nhưng standard is more JSON vì nhận JSON data dễ load hơn vì similar JS Object và succint(cô đọng) giúp save Bandwidth và improve response time khi gửi giữa client và server
VD:
//JSON
{
"employee"[
{"firstName":"John","lastName":"Doe"},
{"firstName":"Anna","lastName":"Smith"},
]
}
//XML
<employee>
<employee>
<firstName>John</firstName><lastName>Doe</lastName>
</employee>
<employee>
<firstName>Anna</firstName><lastName>Smith</lastName>
</employee>
</employee>
+is text,written with javascript object notation
+JSON.parse('[JSON]'):JSON->String
+JSON.stringtify([obj]):string->JSON
AJAX
Mỗi lần ta communicate vs server, t request và browser nhận response và reload page-> mỗi lần update sẽ phải reload entire program again k thích hợp vs lager và complex website
-> request small chunk of data(HTML,XML,plain text,JSON...) và display khi cần thay vì refresh toàn page
->AJAX:allow to read from a web server after the page has loaded and updata a web page without reloading the page.And send data in the background while user interacting with website
AJAX just a technogy for compiling pieces together to achieve. It achieved using a tool browser built call XML HTTP request
VD:+The old way XHR
var request=new XMLHttpRequest();
request.open('GET','/my/url',true);
request.onload=function(){
if(request.status>=200 &&request.status<400){
//success
var data=JSON.parse(request.responseText);
}else{
//We reached our target server, but it returned an error
}
};
request.onerror=function(){
//There was a connection error of some sort
}
request.send();
+The new Old way:jQuery
$.getJSON('/my/url',function(data){
})
+The New Way:Fetch
fetch('/my/url').then(response=>{
console.log(response);
})
->Page update quicker and you don't have to wait for the page to refresh
->Site faster + responsive
->less data is downloaded on each update->less wasted bandwidth
*.json() đi chung vs fetch API, sau khi fetch ta sử dụng then sau đó lấy response.json() để lấy JSON trong response hoặc có thể dùng trong JS
->AJAX:combination of tool(HTTP,fetch API,JSON) to communicate with
PROMISE
-is an object that may produce a single value some time in the future either a resolved value or a reason that it's not resolved(rejected)
-maybe 1 of 3 possible state: fullfill,rejected,pending
const promise=new promise((resolve,reject)=>{
if(true)
{resolve([data])}
else
{reject([data])}
})
Và sau đó ta có thể dùng then hay catch để handle promise
*Promise.all([array of promise]): chờ đợi all resolve của các promise và trả về array promise
Với array url để fetch, ta có thể dùng Promise.all sau đó dùng map: urls.map để fetch API
*Khi bị error 1 phần tử trong array-> all error
ASYNC/AWAIT(ES8)
async function là function trả về promise, code dễ đọc hơn
Thay vì chain .then() như bình thường ta có thể gán await promise function với 1 biến
await dùng để waiting cho function cho đến khi có promise trả về
Để catch error, ta dùng try catch block
VD:
async function fetchUser(){
const resp = await fetch('....')
const data = await resp.json()//trả về promise
console.log(data)
}
ES9(ES2018)
-Object spread operator
VD:
const array=[1,2,3,4,5]
function sum(a,b,c,d,e){
return a+b+c+d+e;
}
sum(...array)
-finally:thường không có parameter, dc gọi dù trả về data hay error từ then(try) hay catch. Khi cần chạy code dù thế nào after promise
-for await of: cho phép loop through async await nếu có multiple.
VD:
const getData = async function(){
const arrayOfPromises=urls.map(url=>fetch(url));
for await (let request of arrayPromises){
const data=await request.json();
console.log(data);
}
}
getData()
REACT-ROUTER
-Sử dụng khi ta muốn tới 1 route mà k làm thay đổi toàn bộ page(chỉ đổi 1 phần 1 hoặc nhiều component)
-npm install react-router-dom
-import {BrowserRouter as Router,Switch,Route} from 'react-router-dom'
-BrowserRouter: để handle routing. Khi dùng bất cứ component nào dc wrap trong <Router> có thể routing
-Route: render component dựa vào URL
VD:
<Router>
<div className="App">
<Nav/>
<Route path="/about" component={About}>
<Route path="/shop" component={Shop}>
</div>
</Router>
*Khi ta thêm một route khác như home "/" nó sẽ xảy ra trường hợp cả 2 component cùng dc hiển thị.
VD:
<Router>
<div className="App">
<Nav/>
<Route path="/" component={Home}>
<Route path="/about" component={About}>
<Route path="/shop" component={Shop}>
</div>
</Router>
->Vì nó check exact path, VD khi ta dùng path ".../shop" vì có "/" nó render ra home và cả shop component
->Dùng Switch. Switch sẽ đi qua các path và khi match URL, nó sẽ dừng
Để dùng ta wrap <Switch> bao quanh <Route>
*Nhưng khi giải quyết bằng switch nó vẫn chỉ dừng lại ở "/" tức render home mặc dù path là ".../about" vì đã match hết chuỗi(ký tự)
->Để giải quyết ta có thể đưa path "/" xuống component đó hoặc xuống dưới cùng
->Hoặc ta cũng có thể dùng thuộc tính "exact" để xác định chính xác path cần và duy nhất component đó sẽ dc render VD: <Route path="/" exact component={Home}>
*Thay vì nhập để thay đổi path trên URL ta có thể nhấn vào và thay đổi path tự động.
import {Link} from 'react-router-dom' và sau đó dùng <Link to='[path tới vd:/about]'> bao quanh các <li> để dùng
React State Management
-import {useState} from 'react' vào file cần sử dụng state
-create state trên return: const [//tên list,set//Tên list]=useState([{},{},...])
set...:function giúp ta set state , tương tự setState
vd:const [movies,setMovies]=useState([{},{},...])
Sau đó ta có thể dùng bằng cách map
VD:return(
<div>
{movies.map(movie=>(<li>{movie.name}</li>))}
</div>
)
Để sử dụng state từ 1 component khác, ta có thể đưa toàn bộ state tới parent component và passdown vào props của các component -> Rất nhiều state không liên quan tới hay thuộc về parent(vd app.js)
*Để giải quyết điều này ta dùng state management. Ta tạo context component và từ context ta pass down tới các component cần:
-tạo [Tên...]Context.js
-tạo context: import {createContext} from 'react'
export const [tên...]Context=createContext(); : bất cứ khi nào muốn dùng information từ provider ta chỉ cần import context này
Provider chỉ cung cấp thông tin tới các component khác nhau qua thuộc tính, ta sẽ wrap provider xung quanh các component muốn access state
VD:
import React,{useState} from 'react'
export const MovieContext=createContext();
export const MovieProvider=()=>{
const [movies,setMovies]=([{},{},...])
return(
<MovieContext.Provider value=[movies,setMovies]>
{props.children}
</MovieContext.Provider>
);
}
-Sau đó ta import {MovieProvider} tới parent component và wrap trong <MovieProvider></MovieProvider>
-Ở component cần state:
import {useContext} from 'react';
import {MovieContext} from '...'
const value=useContext(//context muốn dùng) hoặc
VD: const [movies,setMovies]=useContext(MovieContext)
Cách pass function down in context:
VD
const [name,setName]=useState('')
const [price,setPrice]=useState('')
const updateName=(e)=>{
setName(e.target.value)
}
sau đó ta có thể sử dụng name và value
Với set... ở useState <=> setState
Với set... ở useContext <=> gửi dispatch trong redux tới reducer để nhận state mới
<=>React-Hook
-Rules:
"Only call hooks at top level".Don't call loop inside loops, conditions, or nested functions
"Only call hooks from react functions". Call them from within React functional components and not just any regular JS function
-useState:
The useState hook lets you add state to functional components
In classes, the state is always an object
With the useState hook, the state doesn't have to be an object
The useState hook returns an array with 2 elements
The first element is the current value of the state, and the second element is a state setter function
New state value depends on the previous state value? You can pass a function to the setter function VD setItems(prevState=>...)
When dealing with objects or array, always make sure to spread your state variable and then call the setter funciton
-useEffect
The effect hook lets you perform side effects in functional components
It is a close replacement for componentDidMount, componentDidUpdate and componentWillUnmount
useEffect là 1 function, paramenter đưa vào là function sẽ dc chạy sau "mỗi lần" render của component
VD: useEffect(()=>{.....})
*Vì điều này, để render khi cần thiết(tránh render lại khi state cũ === state mới) bằng cách đưa vào parameter thứ 2 một array để cho biết prop hay state cần theo dõi(nếu prop hay state trong array này thay đổi->useEffect sẽ execute) và nếu value k thay đổi giữa renders thì useEffect sẽ k run
VD: useEffect(()=>{.....},[count])
Để chạy useEffect only once(hay componentDidMount đối vs class) mà k depend vào state nào. Sẽ dc gọi 1 lần duy nhất khi initial render bằng cách truyền parameter thứ 2 là array rỗng -> thể hiện k dựa vào bất cứ state hay props nào nên k cần gọi khi re-render.
*Khi re-render React sẽ so sánh setState của prevState và gtri hiện tại qua === . Vì thế chỉ re-render mỗi khi đổi kiểu dữ liệu và giá trị
VD: useEffect(()=>{.....},[])
Để chạy useEffect để unmount(hay componentWillUnmount đối vs class)
VD: //HookMouse.js
const logMousePosition=e=>{
console.log('Mouse event')
setX(e.clientX)
setY(e.clientY)
}
useEffect(()=>{
console.log('useEffect called')//tất cả sẽ dc chạy 1 lần vì parameter thứ 2 là []
window.addEventListener('mousemove',logMousePosition)
},[])
//MouseContainer.js
const [display,setDisplay]=useState(true)
return (<div>
<button onClick={()=>setDisplay(!display)}>toggle display<button/>
{display && <HookMouse/>}