Compare commits
1256 Commits
0.5-stable
...
0.10-stabl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5b409002b | ||
|
|
9d4baa12a6 | ||
|
|
0606de0db7 | ||
|
|
13817753c6 | ||
|
|
3f37e8e4ab | ||
|
|
fe1b554d9d | ||
|
|
0ecf9f0599 | ||
|
|
acba66fe2e | ||
|
|
661bafb059 | ||
|
|
8f0c1ce7b1 | ||
|
|
3ca2ab8960 | ||
|
|
06844c27a8 | ||
|
|
b2ea0d0e29 | ||
|
|
90682ad1ee | ||
|
|
617de48e53 | ||
|
|
fd4143a198 | ||
|
|
224b6e5a6a | ||
|
|
11707179da | ||
|
|
bfecabf71a | ||
|
|
bcaebecce2 | ||
|
|
6055468d1c | ||
|
|
7ea026e19a | ||
|
|
f7e4667457 | ||
|
|
e88c0b1b1f | ||
|
|
950ecd84ff | ||
|
|
66b027233c | ||
|
|
c28cd1ae1a | ||
|
|
321643a858 | ||
|
|
c29f1823a1 | ||
|
|
424ebb5436 | ||
|
|
94c6396853 | ||
|
|
f832b9ce59 | ||
|
|
d6c5058193 | ||
|
|
59c495511a | ||
|
|
ba717cfc62 | ||
|
|
9af5b6b1c3 | ||
|
|
35321a8908 | ||
|
|
d90046a104 | ||
|
|
d28467796c | ||
|
|
cff284f291 | ||
|
|
7818b9f81f | ||
|
|
76b2e87173 | ||
|
|
a8aa901e1b | ||
|
|
f45ab7c7f4 | ||
|
|
383e385d51 | ||
|
|
bb3916448e | ||
|
|
5936173626 | ||
|
|
1400085fe3 | ||
|
|
6d2dd794ee | ||
|
|
0247d9d625 | ||
|
|
d160715b19 | ||
|
|
5f6d46f696 | ||
|
|
e197768058 | ||
|
|
f893442591 | ||
|
|
c14a26e573 | ||
|
|
6210dd3325 | ||
|
|
1acdd51af3 | ||
|
|
bf6fe2c194 | ||
|
|
e65085846f | ||
|
|
dedf0c20da | ||
|
|
12bdb8d24c | ||
|
|
3b2d176f59 | ||
|
|
68da0eccbe | ||
|
|
593889b87a | ||
|
|
732f4717a6 | ||
|
|
7807413256 | ||
|
|
ec893833ee | ||
|
|
5aaf4dbae9 | ||
|
|
ecea2918cf | ||
|
|
7f24943e5a | ||
|
|
0491d30e7c | ||
|
|
55b0222596 | ||
|
|
b95fbbe4a2 | ||
|
|
e505e47e01 | ||
|
|
e0c487649d | ||
|
|
22057ef61c | ||
|
|
0278f01d95 | ||
|
|
0cec4af8d7 | ||
|
|
8d495f3b6e | ||
|
|
7987e6a51d | ||
|
|
d88d479685 | ||
|
|
3f3187c14f | ||
|
|
c1443e92e6 | ||
|
|
52e8f3fdb0 | ||
|
|
cdf4f07a15 | ||
|
|
6ff116e34b | ||
|
|
d889a01caf | ||
|
|
04f9887f0e | ||
|
|
9b427a322f | ||
|
|
7bbdcdba96 | ||
|
|
5106b793f7 | ||
|
|
83e4ef16e6 | ||
|
|
308c9a0752 | ||
|
|
6a01752f3d | ||
|
|
6fd53815cd | ||
|
|
3efa02da91 | ||
|
|
d9af091244 | ||
|
|
25773ed1b3 | ||
|
|
9e224e615f | ||
|
|
3ce2cd04e2 | ||
|
|
652f5aea28 | ||
|
|
280ff2e5a7 | ||
|
|
5ede7fb619 | ||
|
|
3ea3274ca4 | ||
|
|
2ca810fbf3 | ||
|
|
d9dd9d5cb3 | ||
|
|
9ffd70c688 | ||
|
|
3171436d97 | ||
|
|
9ce7ecc3d9 | ||
|
|
9f9c8bcebf | ||
|
|
ec54dcbd8f | ||
|
|
9766ed5797 | ||
|
|
1d209248ef | ||
|
|
21e06196cd | ||
|
|
4b56947560 | ||
|
|
554b677e60 | ||
|
|
aa70419f9d | ||
|
|
af1b63456e | ||
|
|
ac3051530a | ||
|
|
c5f56f318a | ||
|
|
be2c185888 | ||
|
|
7d0e6c6c0b | ||
|
|
13aa8d37e6 | ||
|
|
06f762da77 | ||
|
|
4ad320dd13 | ||
|
|
521201f121 | ||
|
|
41d30bb7de | ||
|
|
9c87aef67f | ||
|
|
ec8b0d7fbf | ||
|
|
e954a1c0d9 | ||
|
|
1d27770b40 | ||
|
|
4c4446d283 | ||
|
|
a8fc3b940d | ||
|
|
6666538316 | ||
|
|
620c1bc2ff | ||
|
|
99dab49f92 | ||
|
|
9b0534eb77 | ||
|
|
eee04b19e1 | ||
|
|
f734083a17 | ||
|
|
3fe9f9f336 | ||
|
|
e39c19423a | ||
|
|
6203e53d16 | ||
|
|
88a4a566ae | ||
|
|
2f6656e3e9 | ||
|
|
a0ecf47242 | ||
|
|
4b670a08fa | ||
|
|
6b78cfb0f4 | ||
|
|
8df5e55efd | ||
|
|
237adacc3a | ||
|
|
90e996324a | ||
|
|
b2649dd73b | ||
|
|
0217461d16 | ||
|
|
3c4f45fe45 | ||
|
|
6485e21956 | ||
|
|
ae72e6ef91 | ||
|
|
42444f6bb9 | ||
|
|
071d2a947c | ||
|
|
298a05517e | ||
|
|
cbfbb54c1d | ||
|
|
26179d2b79 | ||
|
|
ba78edbed8 | ||
|
|
34b6707132 | ||
|
|
7b773a6b3d | ||
|
|
1dfc5c79f9 | ||
|
|
04111d5228 | ||
|
|
a6c1b91c7d | ||
|
|
f34f0d2912 | ||
|
|
46cae63d2c | ||
|
|
5049fc6b05 | ||
|
|
8b1279e6b2 | ||
|
|
854d1f7c1b | ||
|
|
ab2d59f8b0 | ||
|
|
25cafec4a9 | ||
|
|
61c287c5ea | ||
|
|
7bba8c3257 | ||
|
|
2f0507f730 | ||
|
|
989f6f987d | ||
|
|
e2b006f9ae | ||
|
|
141ff66986 | ||
|
|
da0b34e945 | ||
|
|
cbce621570 | ||
|
|
472be09ff6 | ||
|
|
7144a9f241 | ||
|
|
8aaf5fdbf4 | ||
|
|
445611f3e6 | ||
|
|
b79a3cbd21 | ||
|
|
0790040aac | ||
|
|
2900997b5f | ||
|
|
7eb33ef176 | ||
|
|
5545887a48 | ||
|
|
e29584b49b | ||
|
|
c43b3f406c | ||
|
|
a4d6796705 | ||
|
|
89d4d352e1 | ||
|
|
f3c1383af9 | ||
|
|
c32e398a5c | ||
|
|
95edc396df | ||
|
|
26cd595a98 | ||
|
|
8840ee32f1 | ||
|
|
bb729a5784 | ||
|
|
b99705f690 | ||
|
|
7e7aa21e24 | ||
|
|
1de77f1fbe | ||
|
|
01b68c0e76 | ||
|
|
e59daa8ed8 | ||
|
|
9b405fba24 | ||
|
|
99b80938af | ||
|
|
e13977c0c2 | ||
|
|
42473b2df1 | ||
|
|
970ae44c1f | ||
|
|
a447d30a2e | ||
|
|
36e97bac21 | ||
|
|
9f9ee697f3 | ||
|
|
58ffd39abf | ||
|
|
30faba394d | ||
|
|
93e7778d5f | ||
|
|
b7836c4da6 | ||
|
|
c2904b978e | ||
|
|
8122cadeb4 | ||
|
|
ea803c47ba | ||
|
|
42c837e4dd | ||
|
|
cadd6cbb6c | ||
|
|
c0660ea6e0 | ||
|
|
cb1f8247e5 | ||
|
|
e0dbca1168 | ||
|
|
f81d16960c | ||
|
|
8a47813baa | ||
|
|
792d8aca86 | ||
|
|
112a20ce73 | ||
|
|
c79974db3a | ||
|
|
5795376961 | ||
|
|
8ac5975ad8 | ||
|
|
d8fd1af4a0 | ||
|
|
f457df275d | ||
|
|
39c9b539e9 | ||
|
|
ae7e44ec84 | ||
|
|
f73b894c37 | ||
|
|
4642a70277 | ||
|
|
2f0bb69708 | ||
|
|
916776753f | ||
|
|
1b5af6b405 | ||
|
|
9e160df868 | ||
|
|
9125f68194 | ||
|
|
9ebb40f013 | ||
|
|
7b5da078c6 | ||
|
|
1167aeb453 | ||
|
|
6780b47526 | ||
|
|
3e77f64141 | ||
|
|
827c44fcd3 | ||
|
|
b7ba0f173e | ||
|
|
634e41788a | ||
|
|
47ae865428 | ||
|
|
0d4213001b | ||
|
|
1e7bdc79e1 | ||
|
|
e87c8a2aa4 | ||
|
|
d3c12487fd | ||
|
|
32e1d76612 | ||
|
|
78ac842b4a | ||
|
|
9ebde97c14 | ||
|
|
2013db23d3 | ||
|
|
e872cd0a7c | ||
|
|
a34eed508a | ||
|
|
adcbf0806c | ||
|
|
64afa545dd | ||
|
|
f66f8f0310 | ||
|
|
9ba014fbf1 | ||
|
|
d71736b3ed | ||
|
|
529c971db3 | ||
|
|
b65f5a4d30 | ||
|
|
123ed1f442 | ||
|
|
31bc18d39e | ||
|
|
f4798ebee1 | ||
|
|
67c5d76321 | ||
|
|
a8af11b46d | ||
|
|
30646c9c1e | ||
|
|
8c3ac3203d | ||
|
|
559933655a | ||
|
|
0a9eaab61f | ||
|
|
cebc49e5e6 | ||
|
|
f8349f9614 | ||
|
|
80cbdea144 | ||
|
|
1991e46f1a | ||
|
|
b98f1adf1a | ||
|
|
05ee61d763 | ||
|
|
cc010e3287 | ||
|
|
49ddf905b1 | ||
|
|
ecfd0c1473 | ||
|
|
4a76b52751 | ||
|
|
940c86964d | ||
|
|
ac1c90e864 | ||
|
|
47645854f9 | ||
|
|
acbba1ae67 | ||
|
|
5c953a7bdd | ||
|
|
d1a337b9db | ||
|
|
1012b2ff4b | ||
|
|
6573a726ba | ||
|
|
a5c518f69a | ||
|
|
f02c3c07d3 | ||
|
|
b04df6335a | ||
|
|
fff48c5921 | ||
|
|
cda1d8c779 | ||
|
|
6f305505a7 | ||
|
|
cd87848b7d | ||
|
|
55be7a71c5 | ||
|
|
f37474b75b | ||
|
|
b0757c5182 | ||
|
|
d0502cf3c1 | ||
|
|
3895353326 | ||
|
|
5abcce5343 | ||
|
|
75b58d2ad2 | ||
|
|
94ef6c51fb | ||
|
|
439bca78ed | ||
|
|
9ac27cb551 | ||
|
|
a6749a686f | ||
|
|
12ebf33f89 | ||
|
|
d547374847 | ||
|
|
756bd975b1 | ||
|
|
da587b15d5 | ||
|
|
db6ff14e7d | ||
|
|
8f298fbd69 | ||
|
|
49747347fb | ||
|
|
35d9286781 | ||
|
|
8cf5882447 | ||
|
|
3f243bc4f9 | ||
|
|
fc2805fe03 | ||
|
|
89bcecc76f | ||
|
|
0f4cc6ee84 | ||
|
|
25e56a4540 | ||
|
|
66b290c32f | ||
|
|
6e5956195d | ||
|
|
c544b01cad | ||
|
|
5f1d4d7c14 | ||
|
|
c1c2dd9a89 | ||
|
|
acfef143ae | ||
|
|
30fd3a30b0 | ||
|
|
2e17144ac0 | ||
|
|
40547125f8 | ||
|
|
eb3d516f40 | ||
|
|
1194a040f9 | ||
|
|
42e65ddb3e | ||
|
|
141f3a8ac8 | ||
|
|
d00b11ef03 | ||
|
|
463f940c7f | ||
|
|
26fb009e0c | ||
|
|
9ae002503c | ||
|
|
b199de29a0 | ||
|
|
bc27325d31 | ||
|
|
d8700f04da | ||
|
|
721ac85bf8 | ||
|
|
3141bc5084 | ||
|
|
bc1e950a41 | ||
|
|
e9e44773ee | ||
|
|
94d11ecf05 | ||
|
|
71c10b9f45 | ||
|
|
5f941628e0 | ||
|
|
497dab2ad9 | ||
|
|
4c1a737343 | ||
|
|
73b4f954f2 | ||
|
|
4ebdb2c0ac | ||
|
|
e0262d50f9 | ||
|
|
647e65525c | ||
|
|
8360da2937 | ||
|
|
2f812b6f9b | ||
|
|
c7dd8d4217 | ||
|
|
9c5c1ed902 | ||
|
|
7ad28183b4 | ||
|
|
2031946946 | ||
|
|
b9cd2f0d3d | ||
|
|
2435b66840 | ||
|
|
a528beeda9 | ||
|
|
1a39c3143c | ||
|
|
a21979404c | ||
|
|
9730759322 | ||
|
|
945f788a41 | ||
|
|
8d1d29286a | ||
|
|
17f602f924 | ||
|
|
7aaa3a4ed1 | ||
|
|
3642b6ea62 | ||
|
|
bced44533f | ||
|
|
f9bb6e46f1 | ||
|
|
e14555caed | ||
|
|
aebfd641aa | ||
|
|
9e1c6950b1 | ||
|
|
220687abda | ||
|
|
0dc0b45f3c | ||
|
|
c8a2018228 | ||
|
|
19ff353fdd | ||
|
|
4992423547 | ||
|
|
6d4b470cfc | ||
|
|
9f1ed709d0 | ||
|
|
77c53dd5d4 | ||
|
|
e994e06c54 | ||
|
|
806e879566 | ||
|
|
fa046ca04e | ||
|
|
86373d924c | ||
|
|
5dabba999b | ||
|
|
57bf7d21f3 | ||
|
|
ce95c3d042 | ||
|
|
92fdc1562d | ||
|
|
4e9352f8f8 | ||
|
|
cd2aecc377 | ||
|
|
85270ae154 | ||
|
|
92a20220e7 | ||
|
|
e4d1618f63 | ||
|
|
78f3addd01 | ||
|
|
036303ee90 | ||
|
|
26c6ea961b | ||
|
|
aaada5e212 | ||
|
|
f18bda51d6 | ||
|
|
3119d66e26 | ||
|
|
98432365d9 | ||
|
|
a2e805b26e | ||
|
|
f7949c1c23 | ||
|
|
fce6d114fe | ||
|
|
f1b7db9aef | ||
|
|
f1b54bc310 | ||
|
|
e58064a8db | ||
|
|
bff9731b66 | ||
|
|
1666935878 | ||
|
|
43a242b67f | ||
|
|
5d7563f706 | ||
|
|
4cbc4b58f6 | ||
|
|
b225b34f91 | ||
|
|
32f69713fc | ||
|
|
cf1089fa0e | ||
|
|
00f2a053f0 | ||
|
|
65490a09e6 | ||
|
|
d8e9eb978b | ||
|
|
46c6ac5bb0 | ||
|
|
132e8b3c43 | ||
|
|
4894055114 | ||
|
|
b5dbbd5b2d | ||
|
|
470a7d11ee | ||
|
|
34e6a51e19 | ||
|
|
933681b42c | ||
|
|
0bca41fc93 | ||
|
|
864366d082 | ||
|
|
f368f18b61 | ||
|
|
36fd1def84 | ||
|
|
0e5dfd3fec | ||
|
|
d300df51e1 | ||
|
|
989eb2e7d9 | ||
|
|
526be1570e | ||
|
|
e3342f31b2 | ||
|
|
4aececb645 | ||
|
|
7614af3c9a | ||
|
|
4975113f20 | ||
|
|
ce92efefc0 | ||
|
|
4a5a6ad733 | ||
|
|
62b52e008e | ||
|
|
b1e6c4d0dd | ||
|
|
db04043eaa | ||
|
|
1e702f7258 | ||
|
|
97518fd664 | ||
|
|
38491c7c93 | ||
|
|
ad9c5e9242 | ||
|
|
91ef878ca8 | ||
|
|
2521b47707 | ||
|
|
79995a05c7 | ||
|
|
7b047111a0 | ||
|
|
b872100be6 | ||
|
|
14cb99c9aa | ||
|
|
c16b5659a0 | ||
|
|
0af9c3ebe7 | ||
|
|
95a80591dd | ||
|
|
f0b01d0faa | ||
|
|
1d1a790df0 | ||
|
|
ca02a068b8 | ||
|
|
8b12670ef9 | ||
|
|
2cac321b27 | ||
|
|
9c91546451 | ||
|
|
494f6e9c34 | ||
|
|
e3248efe92 | ||
|
|
559cd46181 | ||
|
|
e931dba107 | ||
|
|
de7a92afa7 | ||
|
|
d829d1ab9b | ||
|
|
b1a949ed45 | ||
|
|
4b392f19a8 | ||
|
|
ffc31ed77b | ||
|
|
df8d092609 | ||
|
|
ca930efa7c | ||
|
|
9558285f09 | ||
|
|
c5f0e14985 | ||
|
|
d8d4120614 | ||
|
|
ea711f1d62 | ||
|
|
4440486a24 | ||
|
|
0d2510ad9c | ||
|
|
79beb71d69 | ||
|
|
d489637a4f | ||
|
|
2ac36178c6 | ||
|
|
487f633643 | ||
|
|
8abca77381 | ||
|
|
71b585325c | ||
|
|
a05cef4a40 | ||
|
|
4f53f58754 | ||
|
|
ef4bda326e | ||
|
|
804280275b | ||
|
|
c2d57dff4b | ||
|
|
c72e906841 | ||
|
|
703a29c0b2 | ||
|
|
76a7e2de75 | ||
|
|
2562813c63 | ||
|
|
89819de4f2 | ||
|
|
b5f905523b | ||
|
|
4bdea53d6e | ||
|
|
9ade3c26d3 | ||
|
|
0906d282ec | ||
|
|
8ca62bd022 | ||
|
|
a69f98b834 | ||
|
|
e1f4357ff7 | ||
|
|
615dedc3e2 | ||
|
|
94727f8223 | ||
|
|
a821f03cf4 | ||
|
|
fd02f2c1cd | ||
|
|
c3a2ea2256 | ||
|
|
977b60c1ed | ||
|
|
091534c376 | ||
|
|
17de85689e | ||
|
|
b131da3869 | ||
|
|
d96c6914c7 | ||
|
|
f62ec225e0 | ||
|
|
9420e86480 | ||
|
|
c885abbf21 | ||
|
|
6c7697a1a9 | ||
|
|
eb2ac7f2f2 | ||
|
|
d9b959884b | ||
|
|
5857eb884c | ||
|
|
2f027fce2d | ||
|
|
ad70848e80 | ||
|
|
c6f91ee6e8 | ||
|
|
ca1ecc626b | ||
|
|
1825f30353 | ||
|
|
124096a9fe | ||
|
|
ad6a982cd0 | ||
|
|
3d47177596 | ||
|
|
ddcab8be99 | ||
|
|
425fd2ca08 | ||
|
|
59cba3e9f7 | ||
|
|
6ebb1cb3ee | ||
|
|
972acb4581 | ||
|
|
2c335b0e57 | ||
|
|
d14ce00dc3 | ||
|
|
d8a8f6a881 | ||
|
|
bcacd17f8b | ||
|
|
f71dbab31a | ||
|
|
73d9d286ee | ||
|
|
49d6d2169d | ||
|
|
1efb14bcf6 | ||
|
|
d6afb5285e | ||
|
|
979ee27e2b | ||
|
|
d73f80ecb2 | ||
|
|
423380f9c3 | ||
|
|
b70c3ef4bb | ||
|
|
ac0373ccae | ||
|
|
095eea3241 | ||
|
|
338ce603f9 | ||
|
|
95cb79a93e | ||
|
|
b713c2c696 | ||
|
|
f5a48f1ff4 | ||
|
|
f47238be41 | ||
|
|
851f08bdc2 | ||
|
|
68bac7fbf0 | ||
|
|
dea6063dc9 | ||
|
|
8dbc530d1c | ||
|
|
1f5c8d21d8 | ||
|
|
2c93cd0267 | ||
|
|
e3e3b477d3 | ||
|
|
4d3a9c87d1 | ||
|
|
87a95155be | ||
|
|
3c40fb2e01 | ||
|
|
2716f38861 | ||
|
|
e2f094614f | ||
|
|
09011493c5 | ||
|
|
0c3628cd8d | ||
|
|
1db788b62c | ||
|
|
2052caf0cc | ||
|
|
76a0a9cba7 | ||
|
|
46f7163f62 | ||
|
|
8d0885e0d8 | ||
|
|
b4f4f10478 | ||
|
|
23ab30ff87 | ||
|
|
b1597ab2d7 | ||
|
|
be42d94f12 | ||
|
|
33fe8eebda | ||
|
|
f0fdabae7b | ||
|
|
a2ecee5353 | ||
|
|
657602135c | ||
|
|
4f57515f91 | ||
|
|
59bd45d594 | ||
|
|
c28e1f24df | ||
|
|
ba6c82a326 | ||
|
|
e23c06a60c | ||
|
|
70a0746e9f | ||
|
|
1e980a146f | ||
|
|
57f208e402 | ||
|
|
f9551d709e | ||
|
|
c75899f277 | ||
|
|
09c8ec51bf | ||
|
|
6fdf36af13 | ||
|
|
5968571952 | ||
|
|
e9484adf65 | ||
|
|
fb858a8fc2 | ||
|
|
4f09a54a1d | ||
|
|
8f2509e169 | ||
|
|
79c9025f17 | ||
|
|
9454282bfc | ||
|
|
147506a911 | ||
|
|
b7b4bcfd2e | ||
|
|
808f60f8a0 | ||
|
|
bd575eb7c8 | ||
|
|
c2be8ba42d | ||
|
|
627d7eb669 | ||
|
|
182a237fa7 | ||
|
|
22ba8b67f1 | ||
|
|
e65726cd04 | ||
|
|
1584aaf746 | ||
|
|
089a494a1f | ||
|
|
9b3342ed34 | ||
|
|
7630e56971 | ||
|
|
9cce0c2752 | ||
|
|
91821007ed | ||
|
|
6dd62b0e4f | ||
|
|
42262f5361 | ||
|
|
2c1a25411f | ||
|
|
13230a3044 | ||
|
|
b366e36367 | ||
|
|
ed3d5add76 | ||
|
|
0e5b62a4c3 | ||
|
|
5b43a2e6d7 | ||
|
|
c01f0a0487 | ||
|
|
c4d918aca0 | ||
|
|
ae9188db50 | ||
|
|
202a3f184d | ||
|
|
605b42e622 | ||
|
|
ee0a4acfac | ||
|
|
e92d769a50 | ||
|
|
33dcf8a0b5 | ||
|
|
80d7d2d0f8 | ||
|
|
309a88bcf6 | ||
|
|
a575e93ecd | ||
|
|
ea40a6aedd | ||
|
|
047e962a55 | ||
|
|
fdfd7c1853 | ||
|
|
be75e3be66 | ||
|
|
c11d6d79f5 | ||
|
|
d270e2b1c7 | ||
|
|
e3e24500ae | ||
|
|
86f2dbe55d | ||
|
|
344b5998a8 | ||
|
|
4de2d39f63 | ||
|
|
7264cbcdfb | ||
|
|
1b67ac90f2 | ||
|
|
29190a2c79 | ||
|
|
bcfb476366 | ||
|
|
1ee7f8131c | ||
|
|
a00e4c840c | ||
|
|
cbefc5a968 | ||
|
|
f3e774559f | ||
|
|
1733d42ded | ||
|
|
cc005668b5 | ||
|
|
5661d5168e | ||
|
|
fb8277c819 | ||
|
|
5aae5a7b1d | ||
|
|
acf0c5c646 | ||
|
|
e915294b68 | ||
|
|
1755d43add | ||
|
|
04ad3bfcc3 | ||
|
|
a78f6f7f94 | ||
|
|
f0b5219df9 | ||
|
|
3396654a6f | ||
|
|
e244df510d | ||
|
|
7a9e5443b7 | ||
|
|
261926303d | ||
|
|
e91a8a1bc3 | ||
|
|
3defe88192 | ||
|
|
7675611e5f | ||
|
|
9a4f011f6c | ||
|
|
c877451887 | ||
|
|
96782fc836 | ||
|
|
1155aa9ac0 | ||
|
|
41526091a0 | ||
|
|
b2e51c6e01 | ||
|
|
a2e352ea76 | ||
|
|
55b7a57e07 | ||
|
|
1d4d1a0be6 | ||
|
|
7dca85a9b1 | ||
|
|
1c90172cd0 | ||
|
|
f871147b4d | ||
|
|
1671efb53a | ||
|
|
8915f1b85d | ||
|
|
92b440b1d7 | ||
|
|
3b0f705658 | ||
|
|
23eac0bbbb | ||
|
|
50d190f111 | ||
|
|
47fe931549 | ||
|
|
b3e1697aad | ||
|
|
4190d0a7bb | ||
|
|
40e2d8a064 | ||
|
|
e1ec9a6c65 | ||
|
|
e2ebbeac07 | ||
|
|
eab2ededdf | ||
|
|
7e29f4607b | ||
|
|
cce91611aa | ||
|
|
76c9d8465e | ||
|
|
abee8b0476 | ||
|
|
82c4e897dc | ||
|
|
17f14d523b | ||
|
|
f5f464b16a | ||
|
|
0647c2ee98 | ||
|
|
f03d6e212a | ||
|
|
918c5134e1 | ||
|
|
8f5ef0fdf2 | ||
|
|
84cacaf5b6 | ||
|
|
72fd24662e | ||
|
|
fdf64919f3 | ||
|
|
ff9ca2ecb2 | ||
|
|
f627bc52b0 | ||
|
|
9f10bb4aca | ||
|
|
a6b888b214 | ||
|
|
cbd6d8a46c | ||
|
|
01b4b23118 | ||
|
|
9e6456ba41 | ||
|
|
a4bb44f1e2 | ||
|
|
fac676073a | ||
|
|
5e6e332d67 | ||
|
|
77697f26e3 | ||
|
|
79b00591f1 | ||
|
|
556065937b | ||
|
|
411f0bd7c3 | ||
|
|
f877c6224f | ||
|
|
f9947dec2a | ||
|
|
e35f4c29bb | ||
|
|
ecf9f8ef6d | ||
|
|
2b0dc71e3d | ||
|
|
cc229eb749 | ||
|
|
633125fd0d | ||
|
|
30f566392b | ||
|
|
6fae670d19 | ||
|
|
b0431a51ca | ||
|
|
02e47ebd00 | ||
|
|
374c9ba658 | ||
|
|
adff7c0238 | ||
|
|
7e0c6bc952 | ||
|
|
0519734ea5 | ||
|
|
b385b580a6 | ||
|
|
91780d1c58 | ||
|
|
a6d8c00b1a | ||
|
|
1070d12732 | ||
|
|
a8216e78b1 | ||
|
|
c211767d47 | ||
|
|
34660eccf9 | ||
|
|
874122bad4 | ||
|
|
63ca84e5af | ||
|
|
d22874d039 | ||
|
|
128a35dff9 | ||
|
|
9e0987cd9b | ||
|
|
82a26ada65 | ||
|
|
9fa759173e | ||
|
|
a31a8c35c2 | ||
|
|
47f24f26aa | ||
|
|
6bd9f35bf3 | ||
|
|
590a5498ab | ||
|
|
d1e955c37b | ||
|
|
1783e54eb0 | ||
|
|
0bbf535b7b | ||
|
|
1f2d57d6a4 | ||
|
|
59f72bd991 | ||
|
|
9f3c4da588 | ||
|
|
9da3f92853 | ||
|
|
814faed08f | ||
|
|
c7fbaa4966 | ||
|
|
ab88dd19d3 | ||
|
|
eab1f4d366 | ||
|
|
c7c72d1a7a | ||
|
|
d914522ae4 | ||
|
|
3431e3f847 | ||
|
|
9d119577ea | ||
|
|
65e0970c41 | ||
|
|
03ab108a77 | ||
|
|
3c5710193c | ||
|
|
9a4a8aa71a | ||
|
|
30672654c5 | ||
|
|
039124bd07 | ||
|
|
5c9f96d12f | ||
|
|
2595cbc676 | ||
|
|
6a8542a6e9 | ||
|
|
a1699bdb88 | ||
|
|
a4595f0b32 | ||
|
|
c0c5cb8e2c | ||
|
|
aabfe79442 | ||
|
|
01c4a706a3 | ||
|
|
9a049d9774 | ||
|
|
47f2cacc6b | ||
|
|
be17771270 | ||
|
|
294bac537d | ||
|
|
b7feb6f6eb | ||
|
|
20d736db4c | ||
|
|
08babd2541 | ||
|
|
41230ef5dd | ||
|
|
e539c8c6c4 | ||
|
|
bf6951687d | ||
|
|
b5cfc72870 | ||
|
|
0bf9910ae9 | ||
|
|
b805eff032 | ||
|
|
df3bd393eb | ||
|
|
f3a6775098 | ||
|
|
c215bc3cd4 | ||
|
|
adfb5f1eae | ||
|
|
d663d42d23 | ||
|
|
7f3d4f0340 | ||
|
|
346c8f5e6e | ||
|
|
93eb6a5637 | ||
|
|
760cdd35c9 | ||
|
|
3ad2938dfa | ||
|
|
5a5137ded4 | ||
|
|
c2920ba84c | ||
|
|
39037eedd1 | ||
|
|
7c95194ec0 | ||
|
|
8fda127748 | ||
|
|
54bac2f07f | ||
|
|
8b0af9b5de | ||
|
|
02de96f012 | ||
|
|
e92ce38cf1 | ||
|
|
decb49a202 | ||
|
|
c7129fd377 | ||
|
|
4b3fa413a1 | ||
|
|
043a986ba9 | ||
|
|
7640e53102 | ||
|
|
b268f95e1f | ||
|
|
8dfdd1d106 | ||
|
|
80e0e2a13f | ||
|
|
5c65abfbac | ||
|
|
904cf15972 | ||
|
|
42dee34146 | ||
|
|
277abbfe7b | ||
|
|
00c8160f8e | ||
|
|
feeebfbc51 | ||
|
|
55f50ca4d1 | ||
|
|
0c366ce648 | ||
|
|
1b477fa40c | ||
|
|
a41c20d43b | ||
|
|
fe8008e67c | ||
|
|
4af362b751 | ||
|
|
8e3cb7bd9d | ||
|
|
c6f99c3a84 | ||
|
|
b8ee94d999 | ||
|
|
3308137d8d | ||
|
|
e944b68e8c | ||
|
|
e560229c83 | ||
|
|
18459deb77 | ||
|
|
a13bd1e251 | ||
|
|
7325189890 | ||
|
|
153b75f186 | ||
|
|
a42b61fa85 | ||
|
|
ce0f244c54 | ||
|
|
9fdf589976 | ||
|
|
ef339c9cc4 | ||
|
|
e5c4a3c7d5 | ||
|
|
036e621467 | ||
|
|
0b97c6438e | ||
|
|
6269cbf482 | ||
|
|
82f211f6b8 | ||
|
|
90e2258791 | ||
|
|
d197992dc8 | ||
|
|
9162cb8abe | ||
|
|
e839405202 | ||
|
|
5466d0a063 | ||
|
|
9270d3d56e | ||
|
|
7d8190f56e | ||
|
|
c313a1045d | ||
|
|
1be9a9e986 | ||
|
|
12e765dd27 | ||
|
|
a7f6082c9c | ||
|
|
2ebbbc5145 | ||
|
|
7db8f818bc | ||
|
|
55e3b64ff4 | ||
|
|
d035268c41 | ||
|
|
d0883c8cc7 | ||
|
|
2807202ee7 | ||
|
|
60f2e45d2d | ||
|
|
c222c46146 | ||
|
|
2b3e97b5a4 | ||
|
|
27b8e7a6f4 | ||
|
|
31359e9962 | ||
|
|
4d6d4b54d6 | ||
|
|
e060eabb01 | ||
|
|
09bdcefd4f | ||
|
|
2bbc42ce41 | ||
|
|
d17bd176a2 | ||
|
|
c2e48740fc | ||
|
|
bf24dc33f7 | ||
|
|
e3ad088ff3 | ||
|
|
1b8bdbe177 | ||
|
|
79b9d5af62 | ||
|
|
66f6cbad56 | ||
|
|
057c88ce52 | ||
|
|
3527d9d91c | ||
|
|
affe7f98b5 | ||
|
|
bcd7b5d194 | ||
|
|
9d443542f9 | ||
|
|
87db648f3e | ||
|
|
6b9fc81b64 | ||
|
|
e4909d0f2e | ||
|
|
9d18956b09 | ||
|
|
cd3bfe64d4 | ||
|
|
241f4d29b2 | ||
|
|
3851462b80 | ||
|
|
76e3294c8f | ||
|
|
d64256fb65 | ||
|
|
00adabc20d | ||
|
|
1cb402c410 | ||
|
|
e923e22c16 | ||
|
|
55cd8bee35 | ||
|
|
4323ab095f | ||
|
|
22dc8fa765 | ||
|
|
e98244adb5 | ||
|
|
92b62bf1fe | ||
|
|
2a84b6c6b2 | ||
|
|
285e3a8929 | ||
|
|
ab36b114fc | ||
|
|
d8a1dbb19c | ||
|
|
cffb115480 | ||
|
|
98b9e2faeb | ||
|
|
11638b7824 | ||
|
|
8fbdb50a9d | ||
|
|
5fbd8109f8 | ||
|
|
126ef094fc | ||
|
|
916ee6b394 | ||
|
|
2104327ba1 | ||
|
|
42eef0e9d6 | ||
|
|
e31fdfd0b3 | ||
|
|
697a9113c0 | ||
|
|
351dcfed01 | ||
|
|
fcfe516a2e | ||
|
|
9886e40395 | ||
|
|
a7811fb75b | ||
|
|
a79ef7fc29 | ||
|
|
15ce8ecfe9 | ||
|
|
92ea31c7b7 | ||
|
|
f4753030a2 | ||
|
|
3bfb687de3 | ||
|
|
eebad16636 | ||
|
|
564c8669f8 | ||
|
|
a7f0afceec | ||
|
|
1f8f0ae2d6 | ||
|
|
0e2840abce | ||
|
|
685dec022a | ||
|
|
e6e71a4953 | ||
|
|
4bd0a40037 | ||
|
|
b99fd93684 | ||
|
|
67c851792a | ||
|
|
3a75d70501 | ||
|
|
b7ef221b27 | ||
|
|
d51ae6b8bc | ||
|
|
61abc645e5 | ||
|
|
2a66c9b089 | ||
|
|
52d3b47f48 | ||
|
|
97bbd852b2 | ||
|
|
af95b35f27 | ||
|
|
c7bb3af760 | ||
|
|
0a3d0163d0 | ||
|
|
566f8b2e85 | ||
|
|
b2507066b6 | ||
|
|
e73900dad4 | ||
|
|
2fe2cd5337 | ||
|
|
04c3e2e407 | ||
|
|
a23d43bf05 | ||
|
|
934ef1d4c2 | ||
|
|
c8b6fe51d9 | ||
|
|
3fd3341ab9 | ||
|
|
060118c7e4 | ||
|
|
3651b8892f | ||
|
|
d49d84b250 | ||
|
|
0df4be849f | ||
|
|
ceaf3fba32 | ||
|
|
42c14b8078 | ||
|
|
9937f0c8bd | ||
|
|
bd1f5e7e16 | ||
|
|
f37fd7a7a3 | ||
|
|
378a49bf3c | ||
|
|
96e97c1a87 | ||
|
|
5f22259964 | ||
|
|
ab47e99215 | ||
|
|
1fcd6412fb | ||
|
|
ce0eec97db | ||
|
|
5d2f0b4e07 | ||
|
|
e79079d174 | ||
|
|
e94ebee15e | ||
|
|
5d878ce914 | ||
|
|
5ae152cdcf | ||
|
|
c6f7fe00fa | ||
|
|
45063aed44 | ||
|
|
5feb745b02 | ||
|
|
eda56b7af2 | ||
|
|
8f96ec255b | ||
|
|
ad0d9e4761 | ||
|
|
b5b60a6acf | ||
|
|
cb6b7f37e7 | ||
|
|
ef5a02c164 | ||
|
|
646421f71f | ||
|
|
4c881d8487 | ||
|
|
5aa901336c | ||
|
|
61c1bf0a41 | ||
|
|
d853c8568e | ||
|
|
b91396be8e | ||
|
|
7df127db31 | ||
|
|
8529f1b053 | ||
|
|
381a3392c6 | ||
|
|
a39b8fda70 | ||
|
|
1e1d7fe770 | ||
|
|
e6010bf75e | ||
|
|
d1fa53ca03 | ||
|
|
26c142df82 | ||
|
|
b61eacd3c5 | ||
|
|
1324eb5556 | ||
|
|
9cb3a3a182 | ||
|
|
f9423241d9 | ||
|
|
5b1e4c0324 | ||
|
|
acbddd2641 | ||
|
|
c821887160 | ||
|
|
4367dad669 | ||
|
|
0ebd3d92ba | ||
|
|
80ab7bf4e1 | ||
|
|
4a9ed4a204 | ||
|
|
f6f3d4262b | ||
|
|
75383c5c99 | ||
|
|
49261c9392 | ||
|
|
fe52e059b9 | ||
|
|
684e5922e8 | ||
|
|
7c1cf0a2dc | ||
|
|
dab167c0e3 | ||
|
|
326e3a33ac | ||
|
|
d44c07b9a7 | ||
|
|
22829b5529 | ||
|
|
c4cd02efc5 | ||
|
|
d1fd4058da | ||
|
|
08bd1f98e5 | ||
|
|
2d6eb3d8fc | ||
|
|
4daeda1490 | ||
|
|
c1925db067 | ||
|
|
cd24cbdbf4 | ||
|
|
d9b7e47824 | ||
|
|
b845134151 | ||
|
|
37bb9b76ab | ||
|
|
39ba5f90b1 | ||
|
|
e3ced21c9d | ||
|
|
66a0f2e7bd | ||
|
|
7c8b70eedb | ||
|
|
f12c428c78 | ||
|
|
7ee30554ad | ||
|
|
6b1042a6f9 | ||
|
|
ff857efdd2 | ||
|
|
0401a0a67c | ||
|
|
5873ee7691 | ||
|
|
da717977ed | ||
|
|
2b763fc452 | ||
|
|
b137a3326e | ||
|
|
970445fc48 | ||
|
|
e716c2ee35 | ||
|
|
e707ec0b1e | ||
|
|
05d44b2152 | ||
|
|
797577576e | ||
|
|
bd535bd51c | ||
|
|
166043593d | ||
|
|
9fd28f44df | ||
|
|
1ffe2d0927 | ||
|
|
735b4f0b7c | ||
|
|
1e71df5399 | ||
|
|
48948c91c3 | ||
|
|
1d73efee10 | ||
|
|
62f7cd213f | ||
|
|
91f6684fbf | ||
|
|
595b482478 | ||
|
|
ff51a23aea | ||
|
|
f7103a8629 | ||
|
|
4c9f9dafa6 | ||
|
|
b65e6a0453 | ||
|
|
ca95c8c3a3 | ||
|
|
3b8af033cd | ||
|
|
b3c87ea017 | ||
|
|
241d57aa9e | ||
|
|
ee8bb07122 | ||
|
|
c2ef6e343d | ||
|
|
192af01952 | ||
|
|
5293a2ab1c | ||
|
|
d5c2d5f291 | ||
|
|
4fe784de1f | ||
|
|
f289e9862a | ||
|
|
5fa707534a | ||
|
|
0a120bb5d0 | ||
|
|
19a5505c50 | ||
|
|
c9401be38e | ||
|
|
b922d8d8a6 | ||
|
|
b8cf7068c4 | ||
|
|
2d6a8391bf | ||
|
|
f4d487fb59 | ||
|
|
be7ee1ee65 | ||
|
|
3e2d3e4837 | ||
|
|
dfb4dde8fd | ||
|
|
159d64ddd3 | ||
|
|
1368b29596 | ||
|
|
c780985d3e | ||
|
|
71772e763a | ||
|
|
2d979a9ce9 | ||
|
|
2b273d8568 | ||
|
|
b725097409 | ||
|
|
772af52f4a | ||
|
|
db299ed761 | ||
|
|
0f274e5b22 | ||
|
|
e086cbb44b | ||
|
|
93c0a46a1d | ||
|
|
2cd663940a | ||
|
|
7bbf6cbfd1 | ||
|
|
46e86df420 | ||
|
|
d64f34b5d8 | ||
|
|
f65f7b3bbd | ||
|
|
c4727944df | ||
|
|
694cd6e9e8 | ||
|
|
465b8dc646 | ||
|
|
284d8d67bd | ||
|
|
b111521f40 | ||
|
|
6a7a15cf30 | ||
|
|
3df6942cde | ||
|
|
fc572832b1 | ||
|
|
46c0aeea67 | ||
|
|
a447f53b00 | ||
|
|
24ec78fd52 | ||
|
|
1393e55d53 | ||
|
|
5640d641d6 | ||
|
|
ecd847cad7 | ||
|
|
b867aa0410 | ||
|
|
8205c681eb | ||
|
|
c4ba8f8997 | ||
|
|
001bda28d9 | ||
|
|
1e7f3f1aac | ||
|
|
28eddd1670 | ||
|
|
a65f60a008 | ||
|
|
091425058b | ||
|
|
e89ad6c960 | ||
|
|
0fed861424 | ||
|
|
e78d580c06 | ||
|
|
e78d5b5462 | ||
|
|
20b7faaab7 | ||
|
|
5dad5e92a9 | ||
|
|
1553bad73a | ||
|
|
aadb65166d | ||
|
|
c8bc605f9e | ||
|
|
486b60486a | ||
|
|
13f0644aaa | ||
|
|
780442f0b3 | ||
|
|
27fa1f5c9c | ||
|
|
dede55d27d | ||
|
|
5c6c02fe03 | ||
|
|
9f3ef1b6ac | ||
|
|
5386cd9665 | ||
|
|
f2ee3c53a9 | ||
|
|
1bcca22719 | ||
|
|
6c1e8e8a66 | ||
|
|
9f69b12e5b | ||
|
|
ff3c8ccbe6 | ||
|
|
da5c61afe4 | ||
|
|
18bf0b80bc | ||
|
|
d220ce71b5 | ||
|
|
d6cbc710bd | ||
|
|
10ccd9f103 | ||
|
|
9e24257a4e | ||
|
|
aedf580a33 | ||
|
|
f713f06c62 | ||
|
|
899ae83acb | ||
|
|
3c1e0f0a8c | ||
|
|
0dc011c40c | ||
|
|
e455e28ff8 | ||
|
|
a4f8ad1bb0 | ||
|
|
0acf5e22bd | ||
|
|
df1099649c | ||
|
|
d1ad4a3ff0 | ||
|
|
2cf7d943df | ||
|
|
9b44ad6ce5 | ||
|
|
7789a32438 | ||
|
|
551cc01430 | ||
|
|
22058d09da | ||
|
|
80efa9a33e | ||
|
|
6a0976ca9d | ||
|
|
5847536c9d | ||
|
|
a5d1e2fd90 | ||
|
|
d8e3779010 | ||
|
|
7d50ab600f | ||
|
|
e3ec6f5292 | ||
|
|
9471287794 | ||
|
|
cbec8c1a89 | ||
|
|
4a7d8f628e | ||
|
|
b025e4c576 | ||
|
|
ee8fa3760d | ||
|
|
efaba68663 | ||
|
|
33effd31d5 | ||
|
|
271e7d50cf | ||
|
|
c235ec7421 | ||
|
|
6e28818ba9 | ||
|
|
95f3caaaa4 | ||
|
|
a7dd6e7c70 | ||
|
|
30ab347b78 | ||
|
|
9585c407e2 | ||
|
|
9efd1f5e9b | ||
|
|
21c5c2a54e | ||
|
|
a970957eef | ||
|
|
119e29ff1d | ||
|
|
7db760427c | ||
|
|
6d2ea9a200 | ||
|
|
0475834470 | ||
|
|
48f1ee4940 | ||
|
|
fb5f69f44e | ||
|
|
e0df9cbb01 | ||
|
|
1e56800543 | ||
|
|
28f30b7ef0 | ||
|
|
86355eb1ba | ||
|
|
bfbcb5362b | ||
|
|
8d2b4a9a25 | ||
|
|
da722b92c0 | ||
|
|
a4d7f3f907 | ||
|
|
6377b2ed95 | ||
|
|
dd52ef92a8 | ||
|
|
9ed72b43e8 | ||
|
|
f4bbe9c296 | ||
|
|
814126dc52 | ||
|
|
ff9246316f | ||
|
|
b92c433c50 | ||
|
|
7144ba1c10 | ||
|
|
0fad22512a | ||
|
|
4d9cde43be | ||
|
|
dc24bb63d6 | ||
|
|
5f296768a5 | ||
|
|
dd5fbc5859 | ||
|
|
280eff41f3 | ||
|
|
214e9103bf | ||
|
|
ac9dd92272 | ||
|
|
25ba629098 | ||
|
|
91d23ffc58 | ||
|
|
10f3d93df7 | ||
|
|
1c77e1a492 | ||
|
|
fbb741febb | ||
|
|
c5cc145538 | ||
|
|
0ef1ca0024 | ||
|
|
0a75a52b4a | ||
|
|
0d2d3360d0 | ||
|
|
15de778587 | ||
|
|
eeefe95958 | ||
|
|
5e65c186aa | ||
|
|
99dcdb87e3 | ||
|
|
58b3ae3136 | ||
|
|
7d6b0dd613 | ||
|
|
893fba8373 | ||
|
|
b46b6a8db9 | ||
|
|
44ad2b55e6 | ||
|
|
820532b7aa | ||
|
|
48281a17e4 |
@@ -2,11 +2,13 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
max_line_length = 80
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = 0
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* text=auto
|
||||
12
.gitignore
vendored
12
.gitignore
vendored
@@ -13,13 +13,9 @@ docs/code
|
||||
docs/_site
|
||||
docs/.sass-cache
|
||||
docs/css/react.css
|
||||
docs/js/.module-cache
|
||||
docs/js/JSXTransformer.js
|
||||
docs/js/react.min.js
|
||||
docs/js/docs.js
|
||||
docs/js/jsx-compiler.js
|
||||
docs/js/live_editor.js
|
||||
docs/js/examples
|
||||
docs/js/*
|
||||
docs/downloads
|
||||
examples/shared/*.js
|
||||
|
||||
test/the-files-to-test.generated.js
|
||||
*.log*
|
||||
chrome-user-data
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"noempty": true,
|
||||
"nonstandard": true,
|
||||
"onecase": true,
|
||||
"sub": true,
|
||||
"regexdash": true,
|
||||
"trailing": true,
|
||||
"undef": true,
|
||||
|
||||
26
.mailmap
26
.mailmap
@@ -1,21 +1,45 @@
|
||||
Ben Newman <bn@cs.stanford.edu> <benjamn@fb.com>
|
||||
Cheng Lou <chenglou92@gmail.com> <chenglou@fb.com>
|
||||
Christoph Pojer <christoph.pojer@gmail.com>
|
||||
Christoph Pojer <christoph.pojer@gmail.com> <cpojer@fb.com>
|
||||
Connor McSheffrey <c@conr.me> <connor.mcsheffrey@gmail.com>
|
||||
Dan Schafer <dschafer@fb.com>
|
||||
Evan Coonrod <evan@paloalto.com>
|
||||
Fabio M. Costa <fabiomcosta@gmail.com> <fabs@fb.com>
|
||||
Harry Hull <harry.hull1@gmail.com>
|
||||
Ingvar Stepanyan <me@rreverser.com> <rreverser@ubuntu.rreverser.a4.internal.cloudapp.net>
|
||||
Jaime Mingo <j.mingov@3boll.com>
|
||||
Jason Bonta <jbonta@gmail.com> <jasonbonta@fb.com>
|
||||
Jason Trill <jason@jasontrill.com>
|
||||
Jeff Morrison <jeff@anafx.com> <Jeff@anafx.com>
|
||||
Jeff Morrison <jeff@anafx.com> JeffMo <jeffmo@fb.com>
|
||||
Jeff Morrison <jeff@anafx.com> <jeffmo@fb.com>
|
||||
Jeffrey Lin <lin.jeffrey@gmail.com> <jeffreylin@fb.com>
|
||||
Jonathan Hsu <jhiswin@gmail.com>
|
||||
Jordan Walke <jordojw@gmail.com>
|
||||
Jordan Walke <jordojw@gmail.com> <jordanjcw@fb.com>
|
||||
Josh Duck <josh@fb.com> <github@joshduck.com>
|
||||
Jun Wu <quark@lihdd.net>
|
||||
Keito Uchiyama <projects@keito.me> <keito@fb.com>
|
||||
Kunal Mehta <k.mehta@berkeley.edu> <kunalm@fb.com>
|
||||
Laurence Rowe <l@lrowe.co.uk> <laurence@lrowe.co.uk>
|
||||
Martin Andert <mandert@gmail.com>
|
||||
Michal Srb <xixixao@seznam.cz> xixixao <xixixao@seznam.cz>
|
||||
Nick Gavalas <njg57@cornell.edu>
|
||||
Nick Thompson <ncthom91@gmail.com> <nickt@instagram.com>
|
||||
Paul O’Shannessy <paul@oshannessy.com> <poshannessy@fb.com>
|
||||
Paul Shen <paul@mnml0.com> <paulshen@fb.com>
|
||||
Pete Hunt <floydophone@gmail.com>
|
||||
Pete Hunt <floydophone@gmail.com> <pete.hunt@fb.com>
|
||||
Pete Hunt <floydophone@gmail.com> <pete@instagram.com>
|
||||
Pete Hunt <floydophone@gmail.com> <phunt@instagram.com>
|
||||
Petri Lievonen <plievone@cc.hut.fi>
|
||||
Pieter Vanderwerff <me@pieter.io> <pieter@heyday.co.nz>
|
||||
Richard Feldman <richard.t.feldman@gmail.com> <richard@noredink.com>
|
||||
Richard Livesey <Livesey7@hotmail.co.uk>
|
||||
Sander Spies <sandermail@gmail.com>
|
||||
Sebastian Markbåge <sebastian@calyptus.eu> <sema@fb.com>
|
||||
Stoyan Stefanov <ssttoo@ymail.com>
|
||||
Thomas Aylott <oblivious@subtlegradient.com> <aylott@fb.com>
|
||||
Timothy Yung <yungsters@gmail.com> <yungsters@fb.com>
|
||||
Vjeux <vjeuxx@gmail.com>
|
||||
Vjeux <vjeuxx@gmail.com> <vjeux@fb.com>
|
||||
|
||||
56
.travis.yml
56
.travis.yml
@@ -2,14 +2,62 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- '0.10'
|
||||
script:
|
||||
- |
|
||||
grunt $TEST_TYPE
|
||||
after_script:
|
||||
- curl -F "react=@build/react.js" -F "react.min=@build/react.min.js" -F "transformer=@build/JSXTransformer.js"
|
||||
-F "react-with-addons=@build/react-with-addons.js" -F "react-with-addons.min=@build/react-with-addons.min.js"
|
||||
-F "commit=$TRAVIS_COMMIT" -F "date=`git log --format='%ct' -1`" -F "pull_request=$TRAVIS_PULL_REQUEST"
|
||||
-F "token=$SECRET_TOKEN" -F "branch=$TRAVIS_BRANCH" $SERVER
|
||||
- |
|
||||
if [ "$TEST_TYPE" = test:full ] && [ "$SERVER" ]; then
|
||||
grunt build
|
||||
curl \
|
||||
-F "react=@build/react.js" \
|
||||
-F "react.min=@build/react.min.js" \
|
||||
-F "transformer=@build/JSXTransformer.js" \
|
||||
-F "react-with-addons=@build/react-with-addons.js" \
|
||||
-F "react-with-addons.min=@build/react-with-addons.min.js" \
|
||||
-F "npm-react=@build/react.tgz" \
|
||||
-F "npm-react-tools=@build/react-tools.tgz" \
|
||||
-F "commit=$TRAVIS_COMMIT" \
|
||||
-F "date=`git log --format='%ct' -1`" \
|
||||
-F "pull_request=$TRAVIS_PULL_REQUEST" \
|
||||
-F "token=$SECRET_TOKEN" \
|
||||
-F "branch=$TRAVIS_BRANCH" \
|
||||
$SERVER
|
||||
fi
|
||||
env:
|
||||
matrix:
|
||||
- TEST_TYPE=test:full
|
||||
- TEST_TYPE=lint
|
||||
- TEST_TYPE=perf:full
|
||||
- TEST_TYPE=test:coverage
|
||||
- TEST_TYPE=test:webdriver:saucelabs BROWSER_NAME=ie11
|
||||
- TEST_TYPE=test:webdriver:saucelabs BROWSER_NAME=ie10
|
||||
- TEST_TYPE=test:webdriver:saucelabs BROWSER_NAME=ie9
|
||||
- TEST_TYPE=test:webdriver:saucelabs BROWSER_NAME=ie8
|
||||
- TEST_TYPE=test:webdriver:saucelabs:ios
|
||||
- TEST_TYPE=test:webdriver:saucelabs BROWSER_NAME=safari
|
||||
global:
|
||||
# SERVER
|
||||
- secure: qPvsJ46XzGrdIuPA70b55xQNGF8jcK7N1LN5CCQYYocXLa+fBrl+fTE77QvehOPhqwJXcj6kOxI+sY0KrVwV7gmq2XY2HZGWUSCxTN0SZlNIzqPA80Y7G/yOjA4PUt8LKgP+8tptyhTAY56qf+hgW8BoLiKOdztYF2p+3zXOLuA=
|
||||
# SECRET_TOKEN
|
||||
- secure: dkpPW+VnoqC/okhRdV90m36NcyBFhcwEKL3bNFExAwi0dXnFao8RoFlvnwiPlA23h2faROkMIetXlti6Aju08BgUFV+f9aL6vLyU7gUent4Nd3413zf2fwDtXIWIETg6uLnOpSykGKgCAT/hY3Q2oPLqOoY0OxfgnbqwxkxljrE=
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- env: TEST_TYPE=lint
|
||||
- env: TEST_TYPE=test:coverage
|
||||
- env: TEST_TYPE=perf:full
|
||||
- env: TEST_TYPE=test:webdriver:saucelabs BROWSER_NAME=ie11
|
||||
- env: TEST_TYPE=test:webdriver:saucelabs BROWSER_NAME=ie10
|
||||
- env: TEST_TYPE=test:webdriver:saucelabs BROWSER_NAME=ie9
|
||||
- env: TEST_TYPE=test:webdriver:saucelabs BROWSER_NAME=ie8
|
||||
- env: TEST_TYPE=test:webdriver:saucelabs:ios
|
||||
- env: TEST_TYPE=test:webdriver:saucelabs BROWSER_NAME=safari
|
||||
notifications:
|
||||
irc:
|
||||
use_notice: true
|
||||
skip_join: true
|
||||
on_success: change
|
||||
on_failure: change
|
||||
channels:
|
||||
- chat.freenode.net#reactjs
|
||||
|
||||
75
AUTHORS
75
AUTHORS
@@ -1,50 +1,121 @@
|
||||
Adam Solove <asolove@gmail.com>
|
||||
Alan deLevie <adelevie@gmail.com>
|
||||
Alex Zelenskiy <azelenskiy@fb.com>
|
||||
Alexander Solovyov <alexander@solovyov.net>
|
||||
Andreas Svensson <andreas@syranide.com>
|
||||
Andrew Davey <andrew@equin.co.uk>
|
||||
Andrew Zich <azich@fb.com>
|
||||
Andrey Popp <8mayday@gmail.com>
|
||||
Ayman Osman <aymano.osman@gmail.com>
|
||||
Ben Alpert <spicyjalapeno@gmail.com>
|
||||
Ben Newman <bn@cs.stanford.edu>
|
||||
Ben Ripkens <bripkens.dev@gmail.com>
|
||||
Bob Eagan <bob@synapsestudios.com>
|
||||
Brian Cooke <bri@bricooke.com>
|
||||
Brian Kim <briankimpossible@gmail.com>
|
||||
Brian Rue <brian@rollbar.com>
|
||||
Cam Spiers <camspiers@gmail.com>
|
||||
Cat Chen <catchen@fb.com>
|
||||
Cheng Lou <chenglou92@gmail.com>
|
||||
Christian Roman <chroman16@gmail.com>
|
||||
Christoph Pojer <christoph.pojer@gmail.com>
|
||||
Clay Allsopp <clay.allsopp@gmail.com>
|
||||
Connor McSheffrey <connor.mcsheffrey@gmail.com>
|
||||
Connor McSheffrey <c@conr.me>
|
||||
Dan Schafer <dschafer@fb.com>
|
||||
Daniel Gasienica <dgasienica@zynga.com>
|
||||
Daniel Lo Nigro <danlo@fb.com>
|
||||
Daniel Miladinov <dmiladinov@wingspan.com>
|
||||
Danny Ben-David <dannybd@fb.com>
|
||||
Daryl Lau <daryl@weak.io>
|
||||
David Hellsing <david@aino.se>
|
||||
David Hu <davidhu91@gmail.com>
|
||||
Dustin Getz <dgetz@wingspan.com>
|
||||
Eric Clemmons <eric@smarterspam.com>
|
||||
Eric Florenzano <floguy@gmail.com>
|
||||
Eric Schoffstall <contra@wearefractal.com>
|
||||
Evan Coonrod <evan@paloalto.com>
|
||||
Fabio M. Costa <fabiomcosta@gmail.com>
|
||||
Felipe Oliveira Carvalho <felipekde@gmail.com>
|
||||
Felix Kling <fkling@fb.com>
|
||||
Fernando Correia <fernando@servicero.com>
|
||||
Greg Hurrell <glh@fb.com>
|
||||
Greg Roodt <groodt@gmail.com>
|
||||
Guido Bouman <m@guido.vc>
|
||||
Harry Hull <harry.hull1@gmail.com>
|
||||
Hugo Jobling <me@thisishugo.com>
|
||||
Ian Obermiller <iano@fb.com>
|
||||
Ingvar Stepanyan <me@rreverser.com>
|
||||
Isaac Salier-Hellendag <isaac@fb.com>
|
||||
Ivan Kozik <ivan@ludios.org>
|
||||
Jaime Mingo <j.mingov@3boll.com>
|
||||
Jakub Malinowski <jakubmal@gmail.com>
|
||||
James Ide <ide@fb.com>
|
||||
Jamie Wong <jamie.lf.wong@gmail.com>
|
||||
Jamison Dance <jergason@gmail.com>
|
||||
Jan Kassens <jkassens@fb.com>
|
||||
Jared Forsyth <jared@jaredforsyth.com>
|
||||
Jason Bonta <jbonta@gmail.com>
|
||||
Jason Trill <jason@jasontrill.com>
|
||||
Jean Lauliac <lauliacj@gmail.com>
|
||||
Jeff Barczewski <jeff.barczewski@gmail.com>
|
||||
Jeff Carpenter <gcarpenterv@gmail.com>
|
||||
Jeff Morrison <jeff@anafx.com>
|
||||
Jeffrey Lin <lin.jeffrey@gmail.com>
|
||||
Jignesh Kakadiya <jigneshhk1992@gmail.com>
|
||||
Jing Chen <jingc@fb.com>
|
||||
Johannes Baiter <johannes.baiter@gmail.com>
|
||||
John Watson <jwatson@fb.com>
|
||||
Jonas Gebhardt <jonas@instagram.com>
|
||||
Jonathan Hsu <jhiswin@gmail.com>
|
||||
Jordan Walke <jordojw@gmail.com>
|
||||
Josh Duck <josh@fb.com>
|
||||
Keito Uchiyama <keito@fb.com>
|
||||
Jun Wu <quark@lihdd.net>
|
||||
Keito Uchiyama <projects@keito.me>
|
||||
Kit Randel <kit@nocturne.net.nz>
|
||||
Kunal Mehta <k.mehta@berkeley.edu>
|
||||
Laurence Rowe <l@lrowe.co.uk>
|
||||
Levi McCallum <levi@levimccallum.com>
|
||||
Lily <qvang.j@gmail.com>
|
||||
Logan Allen <loganfynne@gmail.com>
|
||||
Luigy Leon <luichi.19@gmail.com>
|
||||
Mark Richardson <echo@fb.com>
|
||||
Marshall Roch <mroch@fb.com>
|
||||
Martin Andert <mandert@gmail.com>
|
||||
Martin Konicek <mkonicek@fb.com>
|
||||
Mathieu M-Gosselin <mathieumg@gmail.com>
|
||||
Matt Harrison <mt.harrison86@gmail.com>
|
||||
Matti Nelimarkka <matti.nelimarkka@hiit.fi>
|
||||
Michal Srb <xixixao@seznam.cz>
|
||||
Mouad Debbar <mdebbar@fb.com>
|
||||
Nadeesha Cabral <nadeesha.cabral@gmail.com>
|
||||
Nicholas Bergson-Shilcock <me@nicholasbs.net>
|
||||
Nick Gavalas <njg57@cornell.edu>
|
||||
Nick Thompson <ncthom91@gmail.com>
|
||||
Owen Coutts <owenc@fb.com>
|
||||
Pascal Hartig <passy@twitter.com>
|
||||
Paul O’Shannessy <paul@oshannessy.com>
|
||||
Paul Seiffert <paul.seiffert@gmail.com>
|
||||
Paul Shen <paul@mnml0.com>
|
||||
Pete Hunt <floydophone@gmail.com>
|
||||
Peter Cottle <pcottle@fb.com>
|
||||
Petri Lievonen <plievone@cc.hut.fi>
|
||||
Pieter Vanderwerff <me@pieter.io>
|
||||
Richard D. Worth <rdworth@gmail.com>
|
||||
Richard Feldman <richard.t.feldman@gmail.com>
|
||||
Richard Livesey <Livesey7@hotmail.co.uk>
|
||||
Sander Spies <sandermail@gmail.com>
|
||||
Sean Kinsey <oyvind@fb.com>
|
||||
Sebastian Markbåge <sebastian@calyptus.eu>
|
||||
Shaun Trennery <shaun.trennery@gmail.com>
|
||||
Simon Højberg <r.hackr@gmail.com>
|
||||
Stoyan Stefanov <ssttoo@ymail.com>
|
||||
Sundeep Malladi <sundeep.malladi@gmail.com>
|
||||
Thomas Aylott <oblivious@subtlegradient.com>
|
||||
Timothy Yung <yungsters@gmail.com>
|
||||
Tom Occhino <tomocchino@gmail.com>
|
||||
Ville Immonen <ville.immonen@iki.fi>
|
||||
Vjeux <vjeuxx@gmail.com>
|
||||
Wincent Colaiuta <win@wincent.com>
|
||||
Zach Bruggeman <zbruggeman@me.com>
|
||||
fxbois <fxbois@gmail.com>
|
||||
imagentleman <imagentlemail@gmail.com>
|
||||
|
||||
134
CHANGELOG.md
134
CHANGELOG.md
@@ -1,3 +1,137 @@
|
||||
## 0.10.0 (March 21, 2014)
|
||||
|
||||
### React Core
|
||||
|
||||
#### New Features
|
||||
* Added warnings to help migrate towards descriptors
|
||||
* Made it possible to server render without React-related markup (`data-reactid`, `data-react-checksum`). This DOM will not be mountable by React. [Read the docs for `React.renderComponentToStaticMarkup`](http://facebook.github.io/react/docs/top-level-api.html#react.rendercomponenttostaticmarkup)
|
||||
* Added support for more attributes:
|
||||
* `srcSet` for `<img>` to specify images at different pixel ratios
|
||||
* `textAnchor` for SVG
|
||||
|
||||
#### Bug Fixes
|
||||
* Ensure all void elements don’t insert a closing tag into the markup.
|
||||
* Ensure `className={false}` behaves consistently
|
||||
* Ensure `this.refs` is defined, even if no refs are specified.
|
||||
|
||||
### Addons
|
||||
|
||||
* `update` function to deal with immutable data. [Read the docs](http://facebook.github.io/react/docs/update.html)
|
||||
|
||||
### react-tools
|
||||
* Added an option argument to `transform` function. The only option supported is `harmony`, which behaves the same as `jsx --harmony` on the command line. This uses the ES6 transforms from [jstransform](https://github.com/facebook/jstransform).
|
||||
|
||||
|
||||
## 0.9.0 (February 20, 2014)
|
||||
|
||||
### React Core
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
- The lifecycle methods `componentDidMount` and `componentDidUpdate` no longer receive the root node as a parameter; use `this.getDOMNode()` instead
|
||||
- Whenever a prop is equal to `undefined`, the default value returned by `getDefaultProps` will now be used instead
|
||||
- `React.unmountAndReleaseReactRootNode` was previously deprecated and has now been removed
|
||||
- `React.renderComponentToString` is now synchronous and returns the generated HTML string
|
||||
- Full-page rendering (that is, rendering the `<html>` tag using React) is now supported only when starting with server-rendered markup
|
||||
- On mouse wheel events, `deltaY` is no longer negated
|
||||
- When prop types validation fails, a warning is logged instead of an error thrown (with the production build of React, type checks are now skipped for performance)
|
||||
- On `input`, `select`, and `textarea` elements, `.getValue()` is no longer supported; use `.getDOMNode().value` instead
|
||||
- `this.context` on components is now reserved for internal use by React
|
||||
|
||||
#### New Features
|
||||
|
||||
- React now never rethrows errors, so stack traces are more accurate and Chrome's purple break-on-error stop sign now works properly
|
||||
- Added support for SVG tags `defs`, `linearGradient`, `polygon`, `radialGradient`, `stop`
|
||||
- Added support for more attributes:
|
||||
- `crossOrigin` for CORS requests
|
||||
- `download` and `hrefLang` for `<a>` tags
|
||||
- `mediaGroup` and `muted` for `<audio>` and `<video>` tags
|
||||
- `noValidate` and `formNoValidate` for forms
|
||||
- `property` for Open Graph `<meta>` tags
|
||||
- `sandbox`, `seamless`, and `srcDoc` for `<iframe>` tags
|
||||
- `scope` for screen readers
|
||||
- `span` for `<colgroup>` tags
|
||||
- Added support for defining `propTypes` in mixins
|
||||
- Added `any`, `arrayOf`, `component`, `oneOfType`, `renderable`, `shape` to `React.PropTypes`
|
||||
- Added support for `statics` on component spec for static component methods
|
||||
- On all events, `.currentTarget` is now properly set
|
||||
- On keyboard events, `.key` is now polyfilled in all browsers for special (non-printable) keys
|
||||
- On clipboard events, `.clipboardData` is now polyfilled in IE
|
||||
- On drag events, `.dragTransfer` is now present
|
||||
- Added support for `onMouseOver` and `onMouseOut` in addition to the existing `onMouseEnter` and `onMouseLeave` events
|
||||
- Added support for `onLoad` and `onError` on `<img>` elements
|
||||
- Added support for `onReset` on `<form>` elements
|
||||
- The `autoFocus` attribute is now polyfilled consistently on `input`, `select`, and `textarea`
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
- React no longer adds an `__owner__` property to each component's `props` object; passed-in props are now never mutated
|
||||
- When nesting top-level components (e.g., calling `React.renderComponent` within `componentDidMount`), events now properly bubble to the parent component
|
||||
- Fixed a case where nesting top-level components would throw an error when updating
|
||||
- Passing an invalid or misspelled propTypes type now throws an error
|
||||
- On mouse enter/leave events, `.target`, `.relatedTarget`, and `.type` are now set properly
|
||||
- On composition events, `.data` is now properly normalized in IE9 and IE10
|
||||
- CSS property values no longer have `px` appended for the unitless properties `columnCount`, `flex`, `flexGrow`, `flexShrink`, `lineClamp`, `order`, `widows`
|
||||
- Fixed a memory leak when unmounting children with a `componentWillUnmount` handler
|
||||
- Fixed a memory leak when `renderComponentToString` would store event handlers
|
||||
- Fixed an error that could be thrown when removing form elements during a click handler
|
||||
- Boolean attributes such as `disabled` are rendered without a value (previously `disabled="true"`, now simply `disabled`)
|
||||
- `key` values containing `.` are now supported
|
||||
- Shortened `data-reactid` values for performance
|
||||
- Components now always remount when the `key` property changes
|
||||
- Event handlers are attached to `document` only when necessary, improving performance in some cases
|
||||
- Events no longer use `.returnValue` in modern browsers, eliminating a warning in Chrome
|
||||
- `scrollLeft` and `scrollTop` are no longer accessed on document.body, eliminating a warning in Chrome
|
||||
- General performance fixes, memory optimizations, improvements to warnings and error messages
|
||||
|
||||
### React with Addons
|
||||
|
||||
- `React.addons.TestUtils` was added to help write unit tests
|
||||
- `React.addons.TransitionGroup` was renamed to `React.addons.CSSTransitionGroup`
|
||||
- `React.addons.TransitionGroup` was added as a more general animation wrapper
|
||||
- `React.addons.cloneWithProps` was added for cloning components and modifying their props
|
||||
- Bug fix for adding back nodes during an exit transition for CSSTransitionGroup
|
||||
- Bug fix for changing `transitionLeave` in CSSTransitionGroup
|
||||
- Performance optimizations for CSSTransitionGroup
|
||||
- On checkbox `<input>` elements, `checkedLink` is now supported for two-way binding
|
||||
|
||||
### JSX Compiler and react-tools Package
|
||||
|
||||
- Whitespace normalization has changed; now space between two tags on the same line will be preserved, while newlines between two tags will be removed
|
||||
- The `react-tools` npm package no longer includes the React core libraries; use the `react` package instead.
|
||||
- `displayName` is now added in more cases, improving error messages and names in the React Dev Tools
|
||||
- Fixed an issue where an invalid token error was thrown after a JSX closing tag
|
||||
- `JSXTransformer` now uses source maps automatically in modern browsers
|
||||
- `JSXTransformer` error messages now include the filename and problematic line contents when a file fails to parse
|
||||
|
||||
## 0.8.0 (December 19, 2013)
|
||||
|
||||
### React
|
||||
|
||||
* Added support for more attributes:
|
||||
* `rows` & `cols` for `<textarea>`
|
||||
* `defer` & `async` for `<script>`
|
||||
* `loop` for `<audio>` & `<video>`
|
||||
* `autoCorrect` for form fields (a non-standard attribute only supported by mobile WebKit)
|
||||
* Improved error messages
|
||||
* Fixed Selection events in IE11
|
||||
* Added `onContextMenu` events
|
||||
|
||||
### React with Addons
|
||||
|
||||
* Fixed bugs with TransitionGroup when children were undefined
|
||||
* Added support for `onTransition`
|
||||
|
||||
### react-tools
|
||||
|
||||
* Upgraded `jstransform` and `esprima-fb`
|
||||
|
||||
### JSXTransformer
|
||||
|
||||
* Added support for use in IE8
|
||||
* Upgraded browserify, which reduced file size by ~65KB (16KB gzipped)
|
||||
|
||||
|
||||
## 0.5.2, 0.4.2 (December 18, 2013)
|
||||
|
||||
### React
|
||||
|
||||
@@ -57,6 +57,7 @@ Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe
|
||||
* `"use strict";`
|
||||
* 80 character line length
|
||||
* "Attractive"
|
||||
* Do not use the optional parameters of `setTimeout` and `setInterval`
|
||||
|
||||
## License
|
||||
|
||||
|
||||
195
Gruntfile.js
195
Gruntfile.js
@@ -3,97 +3,206 @@
|
||||
var exec = require('child_process').exec;
|
||||
var jsxTask = require('./grunt/tasks/jsx');
|
||||
var browserifyTask = require('./grunt/tasks/browserify');
|
||||
var wrapupTask = require('./grunt/tasks/wrapup');
|
||||
var populistTask = require('./grunt/tasks/populist');
|
||||
var phantomTask = require('./grunt/tasks/phantom');
|
||||
var webdriverPhantomJSTask = require('./grunt/tasks/webdriver-phantomjs');
|
||||
var webdriverJasmineTasks = require('./grunt/tasks/webdriver-jasmine');
|
||||
var sauceTunnelTask = require('./grunt/tasks/sauce-tunnel');
|
||||
var npmTask = require('./grunt/tasks/npm');
|
||||
var releaseTasks = require('./grunt/tasks/release');
|
||||
var npmReactTasks = require('./grunt/tasks/npm-react');
|
||||
var npmReactToolsTasks = require('./grunt/tasks/npm-react-tools');
|
||||
var versionCheckTask = require('./grunt/tasks/version-check');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
copy: require('./grunt/config/copy'),
|
||||
jsx: require('./grunt/config/jsx/jsx'),
|
||||
jsx: require('./grunt/config/jsx'),
|
||||
browserify: require('./grunt/config/browserify'),
|
||||
wrapup: require('./grunt/config/wrapup'),
|
||||
populist: require('./grunt/config/populist'),
|
||||
phantom: require('./grunt/config/phantom'),
|
||||
connect: require('./grunt/config/server')(grunt),
|
||||
"webdriver-jasmine": require('./grunt/config/webdriver-jasmine'),
|
||||
"webdriver-perf": require('./grunt/config/webdriver-perf'),
|
||||
npm: require('./grunt/config/npm'),
|
||||
clean: ['./build', './*.gem', './docs/_site', './examples/shared/*.js'],
|
||||
clean: ['./build', './*.gem', './docs/_site', './examples/shared/*.js', '.module-cache'],
|
||||
jshint: require('./grunt/config/jshint'),
|
||||
compare_size: require('./grunt/config/compare_size')
|
||||
compare_size: require('./grunt/config/compare_size'),
|
||||
complexity: require('./grunt/config/complexity')
|
||||
});
|
||||
|
||||
grunt.config.set('compress', require('./grunt/config/compress'));
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-compare-size');
|
||||
grunt.loadNpmTasks('grunt-contrib-compress');
|
||||
Object.keys(grunt.file.readJSON('package.json').devDependencies)
|
||||
.filter(function(npmTaskName) { return npmTaskName.indexOf('grunt-') === 0; })
|
||||
.filter(function(npmTaskName) { return npmTaskName != 'grunt-cli'; })
|
||||
.forEach(function(npmTaskName) { grunt.loadNpmTasks(npmTaskName); });
|
||||
|
||||
// Alias 'jshint' to 'lint' to better match the workflow we know
|
||||
grunt.registerTask('lint', ['jshint']);
|
||||
|
||||
// Register jsx:debug and :release tasks.
|
||||
grunt.registerTask('download-previous-version', require('./grunt/tasks/download-previous-version.js'));
|
||||
|
||||
grunt.registerTask('delete-build-modules', function() {
|
||||
if (grunt.file.exists('build/modules')) {
|
||||
grunt.file.delete('build/modules');
|
||||
}
|
||||
});
|
||||
|
||||
// Register jsx:normal and :release tasks.
|
||||
grunt.registerMultiTask('jsx', jsxTask);
|
||||
|
||||
// Our own browserify-based tasks to build a single JS file build
|
||||
grunt.registerMultiTask('browserify', browserifyTask);
|
||||
|
||||
// Similar to Browserify, use WrapUp to generate single JS file that
|
||||
// defines global variables instead of using require.
|
||||
grunt.registerMultiTask('wrapup', wrapupTask);
|
||||
|
||||
grunt.registerMultiTask('populist', populistTask);
|
||||
|
||||
grunt.registerMultiTask('phantom', phantomTask);
|
||||
grunt.registerTask('sauce-tunnel', sauceTunnelTask);
|
||||
|
||||
grunt.registerMultiTask('webdriver-jasmine', webdriverJasmineTasks);
|
||||
|
||||
grunt.registerMultiTask('webdriver-perf', require('./grunt/tasks/webdriver-perf'));
|
||||
|
||||
grunt.registerMultiTask('npm', npmTask);
|
||||
|
||||
// Check that the version we're exporting is the same one we expect in the
|
||||
// package. This is not an ideal way to do this, but makes sure that we keep
|
||||
// them in sync.
|
||||
var reactVersionExp = /\bReact\.version\s*=\s*['"]([^'"]+)['"];/;
|
||||
grunt.registerTask('version-check', function() {
|
||||
var version = reactVersionExp.exec(
|
||||
grunt.file.read('./build/modules/React.js')
|
||||
)[1];
|
||||
var expectedVersion = grunt.config.data.pkg.version;
|
||||
if (version !== expectedVersion) {
|
||||
grunt.log.error('Versions do not match. Expected %s, saw %s', expectedVersion, version);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
grunt.registerTask('npm-react:release', npmReactTasks.buildRelease);
|
||||
grunt.registerTask('npm-react:pack', npmReactTasks.packRelease);
|
||||
grunt.registerTask('npm-react-tools:pack', npmReactToolsTasks.pack);
|
||||
|
||||
grunt.registerTask('build:basic', ['jsx:debug', 'version-check', 'browserify:basic']);
|
||||
grunt.registerTask('build:addons', ['jsx:debug', 'browserify:addons']);
|
||||
grunt.registerTask('build:transformer', ['jsx:debug', 'browserify:transformer']);
|
||||
grunt.registerTask('build:min', ['jsx:release', 'version-check', 'browserify:min']);
|
||||
grunt.registerTask('build:addons-min', ['jsx:debug', 'browserify:addonsMin']);
|
||||
grunt.registerTask('version-check', versionCheckTask);
|
||||
|
||||
grunt.registerTask('build:basic', ['jsx:normal', 'version-check', 'browserify:basic']);
|
||||
grunt.registerTask('build:addons', ['jsx:normal', 'browserify:addons']);
|
||||
grunt.registerTask('build:transformer', ['jsx:normal', 'browserify:transformer']);
|
||||
grunt.registerTask('build:min', ['jsx:normal', 'version-check', 'browserify:min']);
|
||||
grunt.registerTask('build:addons-min', ['jsx:normal', 'browserify:addonsMin']);
|
||||
grunt.registerTask('build:withCodeCoverageLogging', [
|
||||
'jsx:normal',
|
||||
'version-check',
|
||||
'browserify:withCodeCoverageLogging'
|
||||
]);
|
||||
grunt.registerTask('build:perf', [
|
||||
'jsx:normal',
|
||||
'version-check',
|
||||
'browserify:transformer',
|
||||
'browserify:basic',
|
||||
'browserify:min',
|
||||
'download-previous-version'
|
||||
]);
|
||||
grunt.registerTask('build:test', [
|
||||
'jsx:jasmine',
|
||||
'delete-build-modules',
|
||||
'jsx:test',
|
||||
'version-check',
|
||||
'populist:jasmine',
|
||||
'populist:test'
|
||||
]);
|
||||
grunt.registerTask('build:npm-react', ['version-check', 'jsx:normal', 'npm-react:release']);
|
||||
|
||||
grunt.registerTask('test', ['build:test', 'build:basic', 'phantom:run']);
|
||||
grunt.registerTask('webdriver-phantomjs', webdriverPhantomJSTask);
|
||||
|
||||
grunt.registerTask('coverage:parse', require('./grunt/tasks/coverage-parse'));
|
||||
|
||||
grunt.registerTask('test:webdriver:phantomjs', [
|
||||
'connect',
|
||||
'webdriver-phantomjs',
|
||||
'webdriver-jasmine:local'
|
||||
]);
|
||||
|
||||
grunt.registerTask('perf:webdriver:phantomjs', [
|
||||
'connect',
|
||||
'webdriver-phantomjs',
|
||||
'webdriver-perf:local'
|
||||
]);
|
||||
|
||||
grunt.registerTask('test:full', [
|
||||
'build:test',
|
||||
'build:basic',
|
||||
|
||||
'connect',
|
||||
'webdriver-phantomjs',
|
||||
'webdriver-jasmine:local',
|
||||
|
||||
'sauce-tunnel',
|
||||
'webdriver-jasmine:saucelabs_android',
|
||||
'webdriver-jasmine:saucelabs_firefox',
|
||||
'webdriver-jasmine:saucelabs_chrome'
|
||||
]);
|
||||
|
||||
grunt.registerTask('perf:full', [
|
||||
'build:perf',
|
||||
|
||||
'connect',
|
||||
'webdriver-phantomjs',
|
||||
'webdriver-perf:local',
|
||||
|
||||
'sauce-tunnel',
|
||||
'webdriver-perf:saucelabs_firefox',
|
||||
'webdriver-perf:saucelabs_chrome',
|
||||
'webdriver-perf:saucelabs_ie11',
|
||||
'webdriver-perf:saucelabs_ie8',
|
||||
]);
|
||||
|
||||
grunt.registerTask('test:webdriver:saucelabs', [
|
||||
'build:test',
|
||||
'build:basic',
|
||||
|
||||
'connect',
|
||||
'sauce-tunnel',
|
||||
'webdriver-jasmine:saucelabs_' + (process.env.BROWSER_NAME || 'ie8')
|
||||
]);
|
||||
|
||||
grunt.registerTask('test:webdriver:saucelabs:ie', [
|
||||
'build:test',
|
||||
'build:basic',
|
||||
|
||||
'connect',
|
||||
'sauce-tunnel',
|
||||
'webdriver-jasmine:saucelabs_ie8',
|
||||
'webdriver-jasmine:saucelabs_ie9',
|
||||
'webdriver-jasmine:saucelabs_ie10',
|
||||
'webdriver-jasmine:saucelabs_ie11'
|
||||
]);
|
||||
|
||||
grunt.registerTask('test:webdriver:saucelabs:ios', [
|
||||
'build:test',
|
||||
'build:basic',
|
||||
|
||||
'connect',
|
||||
'sauce-tunnel',
|
||||
'webdriver-jasmine:saucelabs_ios6_1',
|
||||
'webdriver-jasmine:saucelabs_ios5_1',
|
||||
'webdriver-jasmine:saucelabs_ios4'
|
||||
]);
|
||||
|
||||
grunt.registerTask('test:coverage', [
|
||||
'build:test',
|
||||
'build:withCodeCoverageLogging',
|
||||
'test:webdriver:phantomjs',
|
||||
'coverage:parse'
|
||||
]);
|
||||
grunt.registerTask('test', function() {
|
||||
if (grunt.option('debug')) {
|
||||
grunt.task.run('build:test', 'build:basic', 'connect:server:keepalive');
|
||||
} else {
|
||||
grunt.task.run('build:test', 'build:basic', 'test:webdriver:phantomjs');
|
||||
}
|
||||
});
|
||||
grunt.registerTask('perf', ['build:perf', 'perf:webdriver:phantomjs']);
|
||||
grunt.registerTask('npm:test', ['build', 'npm:pack']);
|
||||
|
||||
// Optimized build task that does all of our builds. The subtasks will be run
|
||||
// in order so we can take advantage of that and only run jsx:debug once.
|
||||
// in order so we can take advantage of that and only run jsx:normal once.
|
||||
grunt.registerTask('build', [
|
||||
'jsx:debug',
|
||||
'delete-build-modules',
|
||||
'jsx:normal',
|
||||
'version-check',
|
||||
'browserify:basic',
|
||||
'browserify:transformer',
|
||||
'browserify:addons',
|
||||
'jsx:release',
|
||||
'browserify:min',
|
||||
'browserify:addonsMin',
|
||||
'npm-react:release',
|
||||
'npm-react:pack',
|
||||
'npm-react-tools:pack',
|
||||
'copy:react_docs',
|
||||
'compare_size'
|
||||
]);
|
||||
|
||||
14
README.md
14
README.md
@@ -8,6 +8,10 @@ React is a JavaScript library for building user interfaces.
|
||||
|
||||
[Learn how to use React in your own project.](http://facebook.github.io/react/docs/getting-started.html)
|
||||
|
||||
## The `react` npm package has recently changed!
|
||||
|
||||
If you're looking for jeffbski's [React.js](https://github.com/jeffbski/autoflow) project, it's now in `npm` as `autoflow` rather than `react`.
|
||||
|
||||
## Examples
|
||||
|
||||
We have several examples [on the website](http://facebook.github.io/react/). Here is the first one to get you started:
|
||||
@@ -28,7 +32,7 @@ React.renderComponent(
|
||||
|
||||
This example will render "Hello John" into a container on the page.
|
||||
|
||||
You'll notice that we used an XML-like syntax; [we call it JSX](http://facebook.github.io/react/docs/jsx-in-depth.html). JSX is not required to use React, but it makes code more readable, and writing it feels like writing HTML. A simple transform is included with React that allows converting JSX into native JavaScript for browsers to digest.
|
||||
You'll notice that we used an HTML-like syntax; [we call it JSX](http://facebook.github.io/react/docs/jsx-in-depth.html). JSX is not required to use React, but it makes code more readable, and writing it feels like writing HTML. A simple transform is included with React that allows converting JSX into native JavaScript for browsers to digest.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -36,12 +40,12 @@ The fastest way to get started is to serve JavaScript from the CDN (also availab
|
||||
|
||||
```html
|
||||
<!-- The core React library -->
|
||||
<script src="http://fb.me/react-0.5.2.js"></script>
|
||||
<script src="http://fb.me/react-0.10.0.js"></script>
|
||||
<!-- In-browser JSX transformer, remove when pre-compiling JSX. -->
|
||||
<script src="http://fb.me/JSXTransformer-0.5.2.js"></script>
|
||||
<script src="http://fb.me/JSXTransformer-0.10.0.js"></script>
|
||||
```
|
||||
|
||||
We've also built a [starter kit](http://facebook.github.io/react/downloads/react-0.5.2.zip) which might be useful if this is your first time using React. It includes a webpage with an example of using React with live code.
|
||||
We've also built a [starter kit](http://facebook.github.io/react/downloads/react-0.10.0.zip) which might be useful if this is your first time using React. It includes a webpage with an example of using React with live code.
|
||||
|
||||
If you'd like to use [bower](http://bower.io), it's as easy as:
|
||||
|
||||
@@ -83,6 +87,8 @@ We use grunt to automate many tasks. Run `grunt -h` to see a mostly complete lis
|
||||
```sh
|
||||
# Build and run tests with PhantomJS
|
||||
grunt test
|
||||
# Build and run tests in your browser
|
||||
grunt test --debug
|
||||
# Lint the code with JSHint
|
||||
grunt lint
|
||||
# Wipe out build directory
|
||||
|
||||
20
bin/jsx
20
bin/jsx
@@ -1,12 +1,24 @@
|
||||
#!/usr/bin/env node
|
||||
// -*- mode: js -*-
|
||||
"use strict";
|
||||
|
||||
var visitors = require('../vendor/fbtransform/visitors').transformVisitors;
|
||||
var visitors = require('../vendor/fbtransform/visitors');
|
||||
var transform = require('jstransform').transform;
|
||||
|
||||
require("commoner").resolve(function(id) {
|
||||
require('commoner').version(
|
||||
require('../package.json').version
|
||||
).resolve(function(id) {
|
||||
return this.readModuleP(id);
|
||||
}).process(function(id, source) {
|
||||
}).option(
|
||||
'--harmony',
|
||||
'Turns on JS transformations such as ES6 Classes etc.'
|
||||
).process(function(id, source) {
|
||||
// This is where JSX, ES6, etc. desugaring happens.
|
||||
return transform(visitors.react, source).code;
|
||||
var visitorList;
|
||||
if (this.options.harmony) {
|
||||
visitorList = visitors.getAllVisitors();
|
||||
} else {
|
||||
visitorList = visitors.transformVisitors.react;
|
||||
}
|
||||
return transform(visitorList, source).code;
|
||||
});
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#!/usr/bin/env node
|
||||
// -*- mode: js -*-
|
||||
"use strict";
|
||||
|
||||
var visitors = require('../vendor/fbtransform/visitors').transformVisitors;
|
||||
var getAllVisitors = require('../vendor/fbtransform/visitors').getAllVisitors;
|
||||
var transform = require('jstransform').transform;
|
||||
var propagate = require("../vendor/constants").propagate;
|
||||
|
||||
require("commoner").resolve(function(id) {
|
||||
require("commoner").version(
|
||||
require("../package.json").version
|
||||
).resolve(function(id) {
|
||||
var context = this;
|
||||
|
||||
// Note that the result of context.getProvidedP() is cached for the
|
||||
@@ -28,7 +31,7 @@ require("commoner").resolve(function(id) {
|
||||
var constants = context.config.constants || {};
|
||||
|
||||
// This is where JSX, ES6, etc. desugaring happens.
|
||||
source = transform(visitors.react, source).code;
|
||||
source = transform(getAllVisitors(), source).code;
|
||||
|
||||
// Constant propagation means removing any obviously dead code after
|
||||
// replacing constant expressions with literal (boolean) values.
|
||||
|
||||
8
docs/404.md
Normal file
8
docs/404.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
layout: single
|
||||
title: Page Not Found
|
||||
---
|
||||
|
||||
We couldn't find what you were looking for.
|
||||
|
||||
Please contact the owner of the site that linked you to the original URL and let them know their link is broken.
|
||||
@@ -13,8 +13,9 @@ redcarpet:
|
||||
pygments: true
|
||||
name: React
|
||||
markdown: redcarpet
|
||||
react_version: 0.5.2
|
||||
react_version: 0.10.0
|
||||
description: A JavaScript library for building user interfaces
|
||||
relative_permalinks: true
|
||||
paginate: 5
|
||||
paginate_path: /blog/page:num/
|
||||
timezone: America/Los_Angeles
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
@import '_solarized';
|
||||
|
||||
@mixin code-typography {
|
||||
font-family: 'source-code-pro', Menlo, 'Courier New', Consolas, monospace;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
font-family: 'source-code-pro', Menlo, Consolas, 'Courier New', monospace;
|
||||
font-size: 0.8em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
$skinnyContentWidth: 650px;
|
||||
@@ -290,7 +290,7 @@ h1, h2, h3, h4, h5, h6 {
|
||||
|
||||
.marketing-col {
|
||||
float: left;
|
||||
margin-right: 40px;
|
||||
margin-left: 40px;
|
||||
width: $columnWidth;
|
||||
|
||||
h3 {
|
||||
@@ -304,8 +304,8 @@ h1, h2, h3, h4, h5, h6 {
|
||||
}
|
||||
}
|
||||
|
||||
.marketing-col:last-child {
|
||||
margin-right: 0;
|
||||
.marketing-col:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
#examples h3, .home-presentation h3 {
|
||||
@@ -419,7 +419,7 @@ section.black content {
|
||||
|
||||
padding-top: 20px;
|
||||
|
||||
// Make a notice box out of blockquotes in the documetation:
|
||||
// Make a notice box out of blockquotes in the documentation:
|
||||
blockquote {
|
||||
padding: 15px 30px 15px 15px;
|
||||
margin: 20px 0;
|
||||
@@ -428,7 +428,7 @@ section.black content {
|
||||
h4 {
|
||||
margin-top: 0;
|
||||
}
|
||||
p:last-child {
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
// Treat first child as the title - promote to H4.
|
||||
@@ -466,6 +466,12 @@ section.black content {
|
||||
@include code-typography;
|
||||
}
|
||||
}
|
||||
|
||||
.playgroundError {
|
||||
// The compiler view kills padding in order to render the CodeMirror code
|
||||
// more nicely. For the error view, put a padding back
|
||||
padding: 15px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Button */
|
||||
@@ -560,7 +566,7 @@ figure {
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
/* Code Mirror */
|
||||
/* CodeMirror */
|
||||
|
||||
div.CodeMirror pre, div.CodeMirror-linenumber, code {
|
||||
@include code-typography;
|
||||
@@ -574,6 +580,11 @@ div.CodeMirror-linenumber:after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* hide the cursor. Mostly used when code's in plain JS */
|
||||
.CodeMirror-readonly div.CodeMirror-cursor {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
small code,
|
||||
li code,
|
||||
p code {
|
||||
@@ -590,23 +601,28 @@ p code {
|
||||
@include clearfix;
|
||||
}
|
||||
|
||||
.playground::before {
|
||||
.playground-tab {
|
||||
border-bottom: none !important;
|
||||
border-radius: 3px 3px 0 0;
|
||||
padding: 3px 7px;
|
||||
padding: 6px 8px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #c2c0bc;
|
||||
background-color: #f1ede4;
|
||||
content: 'Live editor';
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.playground::before,
|
||||
.playgroundCode,
|
||||
.playground-tab,
|
||||
.playgroundPreview {
|
||||
border: 1px solid rgba(16,16,16,0.1);
|
||||
}
|
||||
|
||||
.playground-tab-active {
|
||||
color: $darkestColor;
|
||||
}
|
||||
|
||||
.playgroundCode {
|
||||
border-radius: 0 3px 3px 3px;
|
||||
float: left;
|
||||
@@ -622,6 +638,11 @@ p code {
|
||||
width: $columnWidth;
|
||||
}
|
||||
|
||||
.playgroundError {
|
||||
color: darken($primary, 5%);
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.MarkdownEditor textarea {
|
||||
width: 100%;
|
||||
height: 100px
|
||||
@@ -636,7 +657,7 @@ p code {
|
||||
padding-left: 9px;
|
||||
}
|
||||
|
||||
/* Codemirror doesn't support <jsx> syntax. Instead of highlighting it
|
||||
/* CodeMirror doesn't support <jsx> syntax. Instead of highlighting it
|
||||
as error, just ignore it */
|
||||
.highlight .javascript .err {
|
||||
background-color: transparent;
|
||||
@@ -662,7 +683,12 @@ p code {
|
||||
}
|
||||
|
||||
.highlight pre code {
|
||||
font-size: inherit;
|
||||
/* Respect line-height defined in <code> styles above */
|
||||
display: block;
|
||||
|
||||
/* Cancel out styles for `li code` in case we have a <pre> within an <li>. */
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.highlight pre .lineno {
|
||||
@@ -723,3 +749,24 @@ p code {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
// Twitter embeds. Need to !important because they inline margin on the iframe.
|
||||
div[data-twttr-id] iframe {
|
||||
margin: 10px auto !important;
|
||||
}
|
||||
|
||||
/* Acknowledgements */
|
||||
|
||||
.three-column {
|
||||
@include clearfix;
|
||||
}
|
||||
|
||||
.three-column > ul {
|
||||
float: left;
|
||||
margin-left: 30px;
|
||||
width: 190px;
|
||||
}
|
||||
|
||||
.three-column > ul:first-child {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,16 @@
|
||||
title: Getting Started
|
||||
- id: tutorial
|
||||
title: Tutorial
|
||||
- id: thinking-in-react
|
||||
title: Thinking in React
|
||||
- title: Community Resources
|
||||
items:
|
||||
- id: videos
|
||||
title: Videos
|
||||
- id: complementary-tools
|
||||
title: Complementary Tools
|
||||
- id: examples
|
||||
title: Examples
|
||||
- title: Guides
|
||||
items:
|
||||
- id: why-react
|
||||
@@ -39,8 +49,12 @@
|
||||
title: Two-Way Binding Helpers
|
||||
- id: class-name-manipulation
|
||||
title: Class Name Manipulation
|
||||
- id: examples
|
||||
title: Examples
|
||||
- id: test-utils
|
||||
title: Test Utilities
|
||||
- id: clone-with-props
|
||||
title: Cloning Components
|
||||
- id: update
|
||||
title: Immutability Helpers
|
||||
- title: Reference
|
||||
items:
|
||||
- id: top-level-api
|
||||
@@ -55,3 +69,13 @@
|
||||
title: Event System
|
||||
- id: dom-differences
|
||||
title: DOM Differences
|
||||
- id: special-non-dom-attributes
|
||||
title: Special Non-DOM Attributes
|
||||
- id: reconciliation
|
||||
title: Reconciliation
|
||||
- title: Flux
|
||||
items:
|
||||
- id: flux-overview
|
||||
title: Flux Overview
|
||||
- id: flux-todo-list
|
||||
title: Flux Todo List
|
||||
|
||||
@@ -28,3 +28,5 @@
|
||||
title: False in JSX
|
||||
- id: communicate-between-components
|
||||
title: Communicate Between Components
|
||||
- id: expose-component-functions
|
||||
title: Expose Component Functions
|
||||
|
||||
2
docs/_js/es5-sham.min.js
vendored
Normal file
2
docs/_js/es5-sham.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
docs/_js/es5-shim.min.js
vendored
Normal file
2
docs/_js/es5-shim.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -6,7 +6,7 @@ var HELLO_COMPONENT = "\
|
||||
/** @jsx React.DOM */\n\
|
||||
var HelloMessage = React.createClass({\n\
|
||||
render: function() {\n\
|
||||
return <div>{'Hello ' + this.props.name}</div>;\n\
|
||||
return <div>Hello {this.props.name}</div>;\n\
|
||||
}\n\
|
||||
});\n\
|
||||
\n\
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
var TIMER_COMPONENT = "\
|
||||
/** @jsx React.DOM */\n\
|
||||
var Timer = React.createClass({\n\
|
||||
getInitialState: function() {\n\
|
||||
return {secondsElapsed: 0};\n\
|
||||
@@ -17,13 +18,13 @@ var Timer = React.createClass({\n\
|
||||
clearInterval(this.interval);\n\
|
||||
},\n\
|
||||
render: function() {\n\
|
||||
return React.DOM.div({},\n\
|
||||
'Seconds Elapsed: ', this.state.secondsElapsed\n\
|
||||
return (\n\
|
||||
<div>Seconds Elapsed: {this.state.secondsElapsed}</div>\n\
|
||||
);\n\
|
||||
}\n\
|
||||
});\n\
|
||||
\n\
|
||||
React.renderComponent(Timer({}), mountNode);\
|
||||
React.renderComponent(<Timer />, mountNode);\
|
||||
";
|
||||
|
||||
React.renderComponent(
|
||||
|
||||
482
docs/_js/html-jsx-lib.js
Normal file
482
docs/_js/html-jsx-lib.js
Normal file
@@ -0,0 +1,482 @@
|
||||
/**
|
||||
* Copyright 2013-2014 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a very simple HTML to JSX converter. It turns out that browsers
|
||||
* have good HTML parsers (who would have thought?) so we utilise this by
|
||||
* inserting the HTML into a temporary DOM node, and then do a breadth-first
|
||||
* traversal of the resulting DOM tree.
|
||||
*/
|
||||
;(function(global) {
|
||||
'use strict';
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType
|
||||
var NODE_TYPE = {
|
||||
ELEMENT: 1,
|
||||
TEXT: 3,
|
||||
COMMENT: 8
|
||||
};
|
||||
var ATTRIBUTE_MAPPING = {
|
||||
'for': 'htmlFor',
|
||||
'class': 'className'
|
||||
};
|
||||
|
||||
/**
|
||||
* Repeats a string a certain number of times.
|
||||
* Also: the future is bright and consists of native string repetition:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat
|
||||
*
|
||||
* @param {string} string String to repeat
|
||||
* @param {number} times Number of times to repeat string. Integer.
|
||||
* @see http://jsperf.com/string-repeater/2
|
||||
*/
|
||||
function repeatString(string, times) {
|
||||
if (times === 1) {
|
||||
return string;
|
||||
}
|
||||
if (times < 0) { throw new Error(); }
|
||||
var repeated = '';
|
||||
while (times) {
|
||||
if (times & 1) {
|
||||
repeated += string;
|
||||
}
|
||||
if (times >>= 1) {
|
||||
string += string;
|
||||
}
|
||||
}
|
||||
return repeated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the string ends with the specified substring.
|
||||
*
|
||||
* @param {string} haystack String to search in
|
||||
* @param {string} needle String to search for
|
||||
* @return {boolean}
|
||||
*/
|
||||
function endsWith(haystack, needle) {
|
||||
return haystack.slice(-needle.length) === needle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim the specified substring off the string. If the string does not end
|
||||
* with the specified substring, this is a no-op.
|
||||
*
|
||||
* @param {string} haystack String to search in
|
||||
* @param {string} needle String to search for
|
||||
* @return {string}
|
||||
*/
|
||||
function trimEnd(haystack, needle) {
|
||||
return endsWith(haystack, needle)
|
||||
? haystack.slice(0, -needle.length)
|
||||
: haystack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a hyphenated string to camelCase.
|
||||
*/
|
||||
function hyphenToCamelCase(string) {
|
||||
return string.replace(/-(.)/g, function(match, chr) {
|
||||
return chr.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified string consists entirely of whitespace.
|
||||
*/
|
||||
function isEmpty(string) {
|
||||
return !/[^\s]/.test(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified string consists entirely of numeric characters.
|
||||
*/
|
||||
function isNumeric(input) {
|
||||
return input !== undefined
|
||||
&& input !== null
|
||||
&& (typeof input === 'number' || parseInt(input, 10) == input);
|
||||
}
|
||||
|
||||
var HTMLtoJSX = function(config) {
|
||||
this.config = config || {};
|
||||
|
||||
if (this.config.createClass === undefined) {
|
||||
this.config.createClass = true;
|
||||
}
|
||||
if (!this.config.indent) {
|
||||
this.config.indent = ' ';
|
||||
}
|
||||
if (!this.config.outputClassName) {
|
||||
this.config.outputClassName = 'NewComponent';
|
||||
}
|
||||
};
|
||||
HTMLtoJSX.prototype = {
|
||||
/**
|
||||
* Reset the internal state of the converter
|
||||
*/
|
||||
reset: function() {
|
||||
this.output = '';
|
||||
this.level = 0;
|
||||
},
|
||||
/**
|
||||
* Main entry point to the converter. Given the specified HTML, returns a
|
||||
* JSX object representing it.
|
||||
* @param {string} html HTML to convert
|
||||
* @return {string} JSX
|
||||
*/
|
||||
convert: function(html) {
|
||||
this.reset();
|
||||
|
||||
// It turns out browsers have good HTML parsers (imagine that).
|
||||
// Let's take advantage of it.
|
||||
var containerEl = document.createElement('div');
|
||||
containerEl.innerHTML = '\n' + this._cleanInput(html) + '\n';
|
||||
|
||||
if (this.config.createClass) {
|
||||
if (this.config.outputClassName) {
|
||||
this.output = 'var ' + this.config.outputClassName + ' = React.createClass({\n';
|
||||
} else {
|
||||
this.output = 'React.createClass({\n';
|
||||
}
|
||||
this.output += this.config.indent + 'render: function() {' + "\n";
|
||||
this.output += this.config.indent + this.config.indent + 'return (\n';
|
||||
}
|
||||
|
||||
if (this._onlyOneTopLevel(containerEl)) {
|
||||
// Only one top-level element, the component can return it directly
|
||||
// No need to actually visit the container element
|
||||
this._traverse(containerEl);
|
||||
} else {
|
||||
// More than one top-level element, need to wrap the whole thing in a
|
||||
// container.
|
||||
this.output += this.config.indent + this.config.indent + this.config.indent;
|
||||
this.level++;
|
||||
this._visit(containerEl);
|
||||
}
|
||||
this.output = this.output.trim() + '\n';
|
||||
if (this.config.createClass) {
|
||||
this.output += this.config.indent + this.config.indent + ');\n';
|
||||
this.output += this.config.indent + '}\n';
|
||||
this.output += '});';
|
||||
}
|
||||
return this.output;
|
||||
},
|
||||
|
||||
/**
|
||||
* Cleans up the specified HTML so it's in a format acceptable for
|
||||
* converting.
|
||||
*
|
||||
* @param {string} html HTML to clean
|
||||
* @return {string} Cleaned HTML
|
||||
*/
|
||||
_cleanInput: function(html) {
|
||||
// Remove unnecessary whitespace
|
||||
html = html.trim();
|
||||
// Ugly method to strip script tags. They can wreak havoc on the DOM nodes
|
||||
// so let's not even put them in the DOM.
|
||||
html = html.replace(/<script(.*?)<\/script>/g, '');
|
||||
return html;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if there's only one top-level node in the DOM tree. That is,
|
||||
* all the HTML is wrapped by a single HTML tag.
|
||||
*
|
||||
* @param {DOMElement} containerEl Container element
|
||||
* @return {boolean}
|
||||
*/
|
||||
_onlyOneTopLevel: function(containerEl) {
|
||||
// Only a single child element
|
||||
if (
|
||||
containerEl.childNodes.length === 1
|
||||
&& containerEl.childNodes[0].nodeType === NODE_TYPE.ELEMENT
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
// Only one element, and all other children are whitespace
|
||||
var foundElement = false;
|
||||
for (var i = 0, count = containerEl.childNodes.length; i < count; i++) {
|
||||
var child = containerEl.childNodes[i];
|
||||
if (child.nodeType === NODE_TYPE.ELEMENT) {
|
||||
if (foundElement) {
|
||||
// Encountered an element after already encountering another one
|
||||
// Therefore, more than one element at root level
|
||||
return false;
|
||||
} else {
|
||||
foundElement = true;
|
||||
}
|
||||
} else if (child.nodeType === NODE_TYPE.TEXT && !isEmpty(child.textContent)) {
|
||||
// Contains text content
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a newline followed by the correct indentation for the current
|
||||
* nesting level
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
_getIndentedNewline: function() {
|
||||
return '\n' + repeatString(this.config.indent, this.level + 2);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles processing the specified node
|
||||
*
|
||||
* @param {Node} node
|
||||
*/
|
||||
_visit: function(node) {
|
||||
this._beginVisit(node);
|
||||
this._traverse(node);
|
||||
this._endVisit(node);
|
||||
},
|
||||
|
||||
/**
|
||||
* Traverses all the children of the specified node
|
||||
*
|
||||
* @param {Node} node
|
||||
*/
|
||||
_traverse: function(node) {
|
||||
this.level++;
|
||||
for (var i = 0, count = node.childNodes.length; i < count; i++) {
|
||||
this._visit(node.childNodes[i]);
|
||||
}
|
||||
this.level--;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle pre-visit behaviour for the specified node.
|
||||
*
|
||||
* @param {Node} node
|
||||
*/
|
||||
_beginVisit: function(node) {
|
||||
switch (node.nodeType) {
|
||||
case NODE_TYPE.ELEMENT:
|
||||
this._beginVisitElement(node);
|
||||
break;
|
||||
|
||||
case NODE_TYPE.TEXT:
|
||||
this._visitText(node);
|
||||
break;
|
||||
|
||||
case NODE_TYPE.COMMENT:
|
||||
this._visitComment(node);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.warn('Unrecognised node type: ' + node.nodeType);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles post-visit behaviour for the specified node.
|
||||
*
|
||||
* @param {Node} node
|
||||
*/
|
||||
_endVisit: function(node) {
|
||||
switch (node.nodeType) {
|
||||
case NODE_TYPE.ELEMENT:
|
||||
this._endVisitElement(node);
|
||||
break;
|
||||
// No ending tags required for these types
|
||||
case NODE_TYPE.TEXT:
|
||||
case NODE_TYPE.COMMENT:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles pre-visit behaviour for the specified element node
|
||||
*
|
||||
* @param {DOMElement} node
|
||||
*/
|
||||
_beginVisitElement: function(node) {
|
||||
var tagName = node.tagName.toLowerCase();
|
||||
var attributes = [];
|
||||
for (var i = 0, count = node.attributes.length; i < count; i++) {
|
||||
attributes.push(this._getElementAttribute(node, node.attributes[i]));
|
||||
}
|
||||
|
||||
this.output += '<' + tagName;
|
||||
if (attributes.length > 0) {
|
||||
this.output += ' ' + attributes.join(' ');
|
||||
}
|
||||
if (node.firstChild) {
|
||||
this.output += '>';
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles post-visit behaviour for the specified element node
|
||||
*
|
||||
* @param {Node} node
|
||||
*/
|
||||
_endVisitElement: function(node) {
|
||||
// De-indent a bit
|
||||
// TODO: It's inefficient to do it this way :/
|
||||
this.output = trimEnd(this.output, this.config.indent);
|
||||
if (node.firstChild) {
|
||||
this.output += '</' + node.tagName.toLowerCase() + '>';
|
||||
} else {
|
||||
this.output += ' />';
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles processing of the specified text node
|
||||
*
|
||||
* @param {TextNode} node
|
||||
*/
|
||||
_visitText: function(node) {
|
||||
var text = node.textContent;
|
||||
// If there's a newline in the text, adjust the indent level
|
||||
if (text.indexOf('\n') > -1) {
|
||||
text = node.textContent.replace(/\n\s*/g, this._getIndentedNewline());
|
||||
}
|
||||
this.output += text;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles processing of the specified text node
|
||||
*
|
||||
* @param {Text} node
|
||||
*/
|
||||
_visitComment: function(node) {
|
||||
// Do not render the comment
|
||||
// Since we remove comments, we also need to remove the next line break so we
|
||||
// don't end up with extra whitespace after every comment
|
||||
//if (node.nextSibling && node.nextSibling.nodeType === NODE_TYPE.TEXT) {
|
||||
// node.nextSibling.textContent = node.nextSibling.textContent.replace(/\n\s*/, '');
|
||||
//}
|
||||
this.output += '{/*' + node.textContent.replace('*/', '* /') + '*/}';
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a JSX formatted version of the specified attribute from the node
|
||||
*
|
||||
* @param {DOMElement} node
|
||||
* @param {object} attribute
|
||||
* @return {string}
|
||||
*/
|
||||
_getElementAttribute: function(node, attribute) {
|
||||
switch (attribute.name) {
|
||||
case 'style':
|
||||
return this._getStyleAttribute(attribute.value);
|
||||
default:
|
||||
var name = ATTRIBUTE_MAPPING[attribute.name] || attribute.name;
|
||||
var result = name + '=';
|
||||
// Numeric values should be output as {123} not "123"
|
||||
if (isNumeric(attribute.value)) {
|
||||
result += '{' + attribute.value + '}';
|
||||
} else {
|
||||
result += '"' + attribute.value.replace('"', '"') + '"';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a JSX formatted version of the specified element styles
|
||||
*
|
||||
* @param {string} styles
|
||||
* @return {string}
|
||||
*/
|
||||
_getStyleAttribute: function(styles) {
|
||||
var jsxStyles = new StyleParser(styles).toJSXString();
|
||||
return 'style={{' + jsxStyles + '}}';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles parsing of inline styles
|
||||
*
|
||||
* @param {string} rawStyle Raw style attribute
|
||||
* @constructor
|
||||
*/
|
||||
var StyleParser = function(rawStyle) {
|
||||
this.parse(rawStyle);
|
||||
};
|
||||
StyleParser.prototype = {
|
||||
/**
|
||||
* Parse the specified inline style attribute value
|
||||
* @param {string} rawStyle Raw style attribute
|
||||
*/
|
||||
parse: function(rawStyle) {
|
||||
this.styles = {};
|
||||
rawStyle.split(';').forEach(function(style) {
|
||||
style = style.trim();
|
||||
var firstColon = style.indexOf(':');
|
||||
var key = style.substr(0, firstColon);
|
||||
var value = style.substr(firstColon + 1).trim();
|
||||
if (key !== '') {
|
||||
this.styles[key] = value;
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert the style information represented by this parser into a JSX
|
||||
* string
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
toJSXString: function() {
|
||||
var output = [];
|
||||
for (var key in this.styles) {
|
||||
if (!this.styles.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
output.push(this.toJSXKey(key) + ': ' + this.toJSXValue(this.styles[key]));
|
||||
}
|
||||
return output.join(', ');
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert the CSS style key to a JSX style key
|
||||
*
|
||||
* @param {string} key CSS style key
|
||||
* @return {string} JSX style key
|
||||
*/
|
||||
toJSXKey: function(key) {
|
||||
return hyphenToCamelCase(key);
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert the CSS style value to a JSX style value
|
||||
*
|
||||
* @param {string} value CSS style value
|
||||
* @return {string} JSX style value
|
||||
*/
|
||||
toJSXValue: function(value) {
|
||||
if (isNumeric(value)) {
|
||||
// If numeric, no quotes
|
||||
return value;
|
||||
} else if (endsWith(value, 'px')) {
|
||||
// "500px" -> 500
|
||||
return trimEnd(value, 'px');
|
||||
} else {
|
||||
// Proably a string, wrap it in quotes
|
||||
return '\'' + value.replace(/'/g, '"') + '\'';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Expose public API
|
||||
global.HTMLtoJSX = HTMLtoJSX;
|
||||
}(window));
|
||||
89
docs/_js/html-jsx.js
Normal file
89
docs/_js/html-jsx.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright 2013-2014 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @jsx React.DOM
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a web interface for the HTML to JSX converter contained in
|
||||
* `html-jsx-lib.js`.
|
||||
*/
|
||||
;(function() {
|
||||
|
||||
var HELLO_COMPONENT = "\
|
||||
<!-- Hello world -->\n\
|
||||
<div class=\"awesome\" style=\"border: 1px solid red\">\n\
|
||||
<label for=\"name\">Enter your name: </label>\n\
|
||||
<input type=\"text\" id=\"name\" />\n\
|
||||
</div>\n\
|
||||
<p>Enter your HTML here</p>\
|
||||
";
|
||||
|
||||
var HTMLtoJSXComponent = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
outputClassName: 'NewComponent',
|
||||
createClass: true
|
||||
};
|
||||
},
|
||||
onReactClassNameChange: function(evt) {
|
||||
this.setState({ outputClassName: evt.target.value });
|
||||
},
|
||||
onCreateClassChange: function(evt) {
|
||||
this.setState({ createClass: evt.target.checked });
|
||||
},
|
||||
setInput: function(input) {
|
||||
this.setState({ input: input });
|
||||
this.convertToJsx();
|
||||
},
|
||||
convertToJSX: function(input) {
|
||||
var converter = new HTMLtoJSX({
|
||||
outputClassName: this.state.outputClassName,
|
||||
createClass: this.state.createClass
|
||||
});
|
||||
return converter.convert(input);
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<div id="options">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={this.state.createClass}
|
||||
onChange={this.onCreateClassChange} />
|
||||
Create class
|
||||
</label>
|
||||
<label style={{display: this.state.createClass ? '' : 'none'}}>
|
||||
·
|
||||
Class name:
|
||||
<input
|
||||
type="text"
|
||||
value={this.state.outputClassName}
|
||||
onChange={this.onReactClassNameChange} />
|
||||
</label>
|
||||
</div>
|
||||
<ReactPlayground
|
||||
codeText={HELLO_COMPONENT}
|
||||
renderCode={true}
|
||||
transformer={this.convertToJSX}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
React.renderComponent(<HTMLtoJSXComponent />, document.getElementById('jsxCompiler'));
|
||||
}());
|
||||
8
docs/_js/html5shiv.min.js
vendored
Normal file
8
docs/_js/html5shiv.min.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
HTML5 Shiv v3.6.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
|
||||
*/
|
||||
(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
|
||||
a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}</style>";
|
||||
c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||
|
||||
"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup main mark meter nav output progress section summary time video",version:"3.6.2",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment();
|
||||
for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document);
|
||||
@@ -6,14 +6,22 @@ var HELLO_COMPONENT = "\
|
||||
/** @jsx React.DOM */\n\
|
||||
var HelloMessage = React.createClass({\n\
|
||||
render: function() {\n\
|
||||
return <div>{'Hello ' + this.props.name}</div>;\n\
|
||||
return <div>Hello {this.props.name}</div>;\n\
|
||||
}\n\
|
||||
});\n\
|
||||
\n\
|
||||
React.renderComponent(<HelloMessage name=\"John\" />, mountNode);\
|
||||
";
|
||||
|
||||
var transformer = function(code) {
|
||||
return JSXTransformer.transform(code).code;
|
||||
}
|
||||
React.renderComponent(
|
||||
<ReactPlayground codeText={HELLO_COMPONENT} renderCode={true} />,
|
||||
<ReactPlayground
|
||||
codeText={HELLO_COMPONENT}
|
||||
renderCode={true}
|
||||
transformer={transformer}
|
||||
showCompiledJSTab={false}
|
||||
/>,
|
||||
document.getElementById('jsxCompiler')
|
||||
);
|
||||
|
||||
@@ -14,26 +14,33 @@ var IS_MOBILE = (
|
||||
);
|
||||
|
||||
var CodeMirrorEditor = React.createClass({
|
||||
componentDidMount: function(root) {
|
||||
if (IS_MOBILE) {
|
||||
return;
|
||||
}
|
||||
componentDidMount: function() {
|
||||
if (IS_MOBILE) return;
|
||||
|
||||
this.editor = CodeMirror.fromTextArea(this.refs.editor.getDOMNode(), {
|
||||
mode: 'javascript',
|
||||
lineNumbers: false,
|
||||
lineWrapping: true,
|
||||
smartIndent: false, // javascript mode does bad things with jsx indents
|
||||
matchBrackets: true,
|
||||
theme: 'solarized-light',
|
||||
readOnly: this.props.readOnly
|
||||
});
|
||||
this.editor.on('change', this.onChange);
|
||||
this.onChange();
|
||||
this.editor.on('change', this.handleChange);
|
||||
},
|
||||
onChange: function() {
|
||||
if (this.props.onChange) {
|
||||
var content = this.editor.getValue();
|
||||
this.props.onChange(content);
|
||||
|
||||
componentDidUpdate: function() {
|
||||
if (this.props.readOnly) {
|
||||
this.editor.setValue(this.props.codeText);
|
||||
}
|
||||
},
|
||||
|
||||
handleChange: function() {
|
||||
if (!this.props.readOnly) {
|
||||
this.props.onChange && this.props.onChange(this.editor.getValue());
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// wrap in a div to fully contain CodeMirror
|
||||
var editor;
|
||||
@@ -45,52 +52,115 @@ var CodeMirrorEditor = React.createClass({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={this.props.className}>
|
||||
<div style={this.props.style} className={this.props.className}>
|
||||
{editor}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var selfCleaningTimeout = {
|
||||
componentDidUpdate: function() {
|
||||
clearTimeout(this.timeoutID);
|
||||
},
|
||||
|
||||
setTimeout: function() {
|
||||
clearTimeout(this.timeoutID);
|
||||
this.timeoutID = setTimeout.apply(null, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
var ReactPlayground = React.createClass({
|
||||
MODES: {XJS: 'XJS', JS: 'JS'}, //keyMirror({XJS: true, JS: true}),
|
||||
mixins: [selfCleaningTimeout],
|
||||
|
||||
MODES: {JSX: 'JSX', JS: 'JS'}, //keyMirror({JSX: true, JS: true}),
|
||||
|
||||
propTypes: {
|
||||
codeText: React.PropTypes.string.isRequired,
|
||||
transformer: React.PropTypes.func,
|
||||
renderCode: React.PropTypes.bool,
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
transformer: function(code) {
|
||||
return JSXTransformer.transform(code).code;
|
||||
},
|
||||
showCompiledJSTab: true
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {mode: this.MODES.XJS, code: this.props.codeText};
|
||||
return {
|
||||
mode: this.MODES.JSX,
|
||||
code: this.props.codeText,
|
||||
};
|
||||
},
|
||||
|
||||
bindState: function(name) {
|
||||
return function(value) {
|
||||
var newState = {};
|
||||
newState[name] = value;
|
||||
this.setState(newState);
|
||||
}.bind(this);
|
||||
handleCodeChange: function(value) {
|
||||
this.setState({code: value});
|
||||
this.executeCode();
|
||||
},
|
||||
|
||||
getDesugaredCode: function() {
|
||||
return JSXTransformer.transform(this.state.code).code;
|
||||
handleCodeModeSwitch: function(mode) {
|
||||
this.setState({mode: mode});
|
||||
},
|
||||
|
||||
compileCode: function() {
|
||||
return this.props.transformer(this.state.code);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var content;
|
||||
if (this.state.mode === this.MODES.XJS) {
|
||||
content =
|
||||
<CodeMirrorEditor
|
||||
onChange={this.bindState('code')}
|
||||
className="playgroundStage"
|
||||
codeText={this.state.code}
|
||||
/>;
|
||||
} else if (this.state.mode === this.MODES.JS) {
|
||||
content =
|
||||
<div className="playgroundJS playgroundStage">
|
||||
{this.getDesugaredCode()}
|
||||
</div>;
|
||||
}
|
||||
var isJS = this.state.mode === this.MODES.JS;
|
||||
var compiledCode = '';
|
||||
try {
|
||||
compiledCode = this.compileCode();
|
||||
} catch (err) {}
|
||||
|
||||
var JSContent =
|
||||
<CodeMirrorEditor
|
||||
key="js"
|
||||
className="playgroundStage CodeMirror-readonly"
|
||||
onChange={this.handleCodeChange}
|
||||
codeText={compiledCode}
|
||||
readOnly={true}
|
||||
/>;
|
||||
|
||||
var JSXContent =
|
||||
<CodeMirrorEditor
|
||||
key="jsx"
|
||||
onChange={this.handleCodeChange}
|
||||
className="playgroundStage"
|
||||
codeText={this.state.code}
|
||||
/>;
|
||||
|
||||
var JSXTabClassName =
|
||||
'playground-tab' + (isJS ? '' : ' playground-tab-active');
|
||||
var JSTabClassName =
|
||||
'playground-tab' + (isJS ? ' playground-tab-active' : '');
|
||||
|
||||
var JSTab =
|
||||
<div
|
||||
className={JSTabClassName}
|
||||
onClick={this.handleCodeModeSwitch.bind(this, this.MODES.JS)}>
|
||||
Compiled JS
|
||||
</div>;
|
||||
|
||||
var JSXTab =
|
||||
<div
|
||||
className={JSXTabClassName}
|
||||
onClick={this.handleCodeModeSwitch.bind(this, this.MODES.JSX)}>
|
||||
Live JSX Editor
|
||||
</div>
|
||||
|
||||
return (
|
||||
<div className="playground">
|
||||
<div>
|
||||
{JSXTab}
|
||||
{this.props.showCompiledJSTab && JSTab}
|
||||
</div>
|
||||
<div className="playgroundCode">
|
||||
{content}
|
||||
{isJS ? JSContent : JSXContent}
|
||||
</div>
|
||||
<div className="playgroundPreview">
|
||||
<div ref="mount" />
|
||||
@@ -98,35 +168,43 @@ var ReactPlayground = React.createClass({
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.executeCode();
|
||||
},
|
||||
componentDidUpdate: function() {
|
||||
this.executeCode();
|
||||
|
||||
componentWillUpdate: function(nextProps, nextState) {
|
||||
// execute code only when the state's not being updated by switching tab
|
||||
// this avoids re-displaying the error, which comes after a certain delay
|
||||
if (this.state.code !== nextState.code) {
|
||||
this.executeCode();
|
||||
}
|
||||
},
|
||||
|
||||
executeCode: function() {
|
||||
var mountNode = this.refs.mount.getDOMNode();
|
||||
|
||||
try {
|
||||
React.unmountAndReleaseReactRootNode(mountNode);
|
||||
React.unmountComponentAtNode(mountNode);
|
||||
} catch (e) { }
|
||||
|
||||
try {
|
||||
var desugaredCode = this.getDesugaredCode();
|
||||
var compiledCode = this.compileCode();
|
||||
if (this.props.renderCode) {
|
||||
React.renderComponent(
|
||||
<CodeMirrorEditor codeText={desugaredCode} readOnly={true} />,
|
||||
<CodeMirrorEditor codeText={compiledCode} readOnly={true} />,
|
||||
mountNode
|
||||
);
|
||||
} else {
|
||||
eval(desugaredCode);
|
||||
eval(compiledCode);
|
||||
}
|
||||
} catch (e) {
|
||||
React.renderComponent(
|
||||
<div content={e.toString()} className="playgroundError" />,
|
||||
mountNode
|
||||
);
|
||||
} catch (err) {
|
||||
this.setTimeout(function() {
|
||||
React.renderComponent(
|
||||
<div className="playgroundError">{err.toString()}</div>,
|
||||
mountNode
|
||||
);
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE]><![endif]-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
@@ -15,16 +16,21 @@
|
||||
<link rel="shortcut icon" href="/react/favicon.ico">
|
||||
<link rel="alternate" type="application/rss+xml" title="{{ site.name }}" href="{{ site.url }}{{ site.baseurl }}/feed.xml">
|
||||
|
||||
<link rel="stylesheet" href="/react/css/react.css">
|
||||
<link rel="stylesheet" href="/react/css/syntax.css">
|
||||
<link rel="stylesheet" href="/react/css/codemirror.css">
|
||||
<link rel="stylesheet" href="/react/css/react.css">
|
||||
|
||||
<script type="text/javascript" src="//use.typekit.net/vqa1hcx.js"></script>
|
||||
<script type="text/javascript">try{Typekit.load();}catch(e){}</script>
|
||||
|
||||
<!--[if lte IE 8]>
|
||||
<script type="text/javascript" src="/react/js/html5shiv.min.js"></script>
|
||||
<script type="text/javascript" src="/react/js/es5-shim.min.js"></script>
|
||||
<script type="text/javascript" src="/react/js/es5-sham.min.js"></script>
|
||||
<![endif]-->
|
||||
<script type="text/javascript" src="/react/js/codemirror.js"></script>
|
||||
<script type="text/javascript" src="/react/js/javascript.js"></script>
|
||||
<script type="text/javascript" src="/react/js/react.min.js"></script>
|
||||
<script type="text/javascript" src="/react/js/react.js"></script>
|
||||
<script type="text/javascript" src="/react/js/JSXTransformer.js"></script>
|
||||
<script type="text/javascript" src="/react/js/live_editor.js"></script>
|
||||
<script type="text/javascript" src="/react/js/showdown.js"></script>
|
||||
@@ -40,13 +46,12 @@
|
||||
React
|
||||
</a>
|
||||
<ul class="nav-site">
|
||||
<li><a href="/react/docs/getting-started.html"{% if page.sectionid == 'docs' %} class="active"{% endif %}>docs</a></li>
|
||||
<li><a href="/react/docs/getting-started.html"{% if page.sectionid == 'docs' or page.sectionid == 'tips' %} class="active"{% endif %}>docs</a></li>
|
||||
<li><a href="/react/support.html"{% if page.id == 'support' %} class="active"{% endif %}>support</a></li>
|
||||
<li><a href="/react/downloads.html"{% if page.id == 'downloads' %} class="active"{% endif %}>download</a></li>
|
||||
<li><a href="/react/blog/"{% if page.sectionid == 'blog' %} class="active"{% endif %}>blog</a></li>
|
||||
<li><a href="http://github.com/facebook/react">github</a>
|
||||
</ul>
|
||||
<!-- <iframe src="http://ghbtns.com/github-btn.html?user=facebook&repo=react.js&type=fork"allowtransparency="true" frameborder="0" scrolling="0" width="62" height="20"></iframe> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -69,8 +74,11 @@
|
||||
{{ content }}
|
||||
|
||||
<footer class="wrap">
|
||||
<div class="left">A Facebook & Instagram collaboration.</div>
|
||||
<div class="right">© 2013 Facebook Inc.</div>
|
||||
<div class="left">
|
||||
A Facebook & Instagram collaboration.<br>
|
||||
<a href="/react/acknowledgements.html">Acknowledgements</a>
|
||||
</div>
|
||||
<div class="right">© 2014 Facebook Inc.</div>
|
||||
</footer>
|
||||
</div>
|
||||
<div id="fb-root"></div>
|
||||
|
||||
@@ -19,7 +19,5 @@ sectionid: docs
|
||||
<a class="docs-next" href="/react/docs/{{ page.next }}">Next →</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="fb-comments" data-width="650" data-num-posts="10" data-href="{{ site.url }}{{ site.baseurl }}{{ page.url }}"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -16,6 +16,5 @@ sectionid: blog
|
||||
</div>
|
||||
|
||||
<div class="fb-like" data-send="true" data-width="650" data-show-faces="false"></div>
|
||||
<div class="fb-comments" data-width="650" data-num-posts="10" data-href="{{ site.url }}{{ site.baseurl }}{{ page.url }}"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -19,7 +19,5 @@ sectionid: tips
|
||||
<a class="docs-next" href="/react/tips/{{ page.next }}">Next →</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="fb-comments" data-width="650" data-num-posts="10" data-href="{{ site.url }}{{ site.baseurl }}{{ page.url }}"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -31,8 +31,8 @@ to render views, which we see as an advantage over templates for a few reasons:
|
||||
**no manual string concatenation** and therefore less surface area for XSS
|
||||
vulnerabilities.
|
||||
|
||||
We've also created [JSX](http://facebook.github.io/react/docs/syntax.html), an optional
|
||||
syntax extension, in case you prefer the readability of HTML to raw JavaScript.
|
||||
We've also created [JSX](/react/docs/jsx-in-depth.html), an optional syntax
|
||||
extension, in case you prefer the readability of HTML to raw JavaScript.
|
||||
|
||||
## Reactive updates are dead simple.
|
||||
|
||||
@@ -41,7 +41,7 @@ React really shines when your data changes over time.
|
||||
In a traditional JavaScript application, you need to look at what data changed
|
||||
and imperatively make changes to the DOM to keep it up-to-date. Even AngularJS,
|
||||
which provides a declarative interface via directives and data binding [requires
|
||||
a linking function to manually update DOM nodes](http://docs.angularjs.org/guide/directive#reasonsbehindthecompilelinkseparation).
|
||||
a linking function to manually update DOM nodes](http://code.angularjs.org/1.0.8/docs/guide/directive#reasonsbehindthecompilelinkseparation).
|
||||
|
||||
React takes a different approach.
|
||||
|
||||
@@ -75,17 +75,15 @@ some pretty cool things with it:
|
||||
- We've built internal prototypes that run React apps in a web worker and use
|
||||
React to drive **native iOS views** via an Objective-C bridge.
|
||||
- You can run React
|
||||
[on the server](http://github.com/petehunt/react-server-rendering)
|
||||
[on the server](http://github.com/petehunt/react-server-rendering-example)
|
||||
for SEO, performance, code sharing and overall flexibility.
|
||||
- Events behave in a consistent, standards-compliant way in all browsers
|
||||
(including IE8) and automatically use
|
||||
[event delegation](http://davidwalsh.name/event-delegate).
|
||||
|
||||
Head on over to
|
||||
[facebook.github.io/react](http://facebook.github.io/react) to check
|
||||
out what we have built. Our documentation is geared towards building
|
||||
apps with the framework, but if you are interested in the
|
||||
nuts and bolts
|
||||
[get in touch](http://facebook.github.io/react/support.html) with us!
|
||||
Head on over to [facebook.github.io/react](/react) to check out what we have
|
||||
built. Our documentation is geared towards building apps with the framework,
|
||||
but if you are interested in the nuts and bolts
|
||||
[get in touch](/react/support.html) with us!
|
||||
|
||||
Thanks for reading!
|
||||
|
||||
@@ -59,7 +59,7 @@ Now that we've identified the components in our mock, let's arrange them into a
|
||||
|
||||
<iframe width="100%" height="300" src="http://jsfiddle.net/6wQMG/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
|
||||
|
||||
Now that you have your component hierarchy it's time to start implementing your app. The easiest way is to build a version that takes your data model and renders the UI but has no interactivity. It's easiest to decouple these processes because building building a static version requires a lot of typing and no thinking, and adding interactivity requires a lot of thinking and not a lot of typing. We'll see why.
|
||||
Now that you have your component hierarchy it's time to start implementing your app. The easiest way is to build a version that takes your data model and renders the UI but has no interactivity. It's easiest to decouple these processes because building a static version requires a lot of typing and no thinking, and adding interactivity requires a lot of thinking and not a lot of typing. We'll see why.
|
||||
|
||||
To build a static version of your app that renders your data model you'll want to build components that reuse other components and pass data using *props*. *props* are a way of passing data from parent to child. If you're familiar with the concept of *state*, **don't use state at all** to build this static version. State is reserved only for interactivity, that is, data that changes over time. Since this is a static version of the app you don't need it.
|
||||
|
||||
|
||||
48
docs/_posts/2013-12-19-react-v0.8.0.md
Normal file
48
docs/_posts/2013-12-19-react-v0.8.0.md
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
title: "React v0.8"
|
||||
layout: post
|
||||
author: Paul O'Shannessy
|
||||
---
|
||||
|
||||
I'll start by answering the obvious question:
|
||||
|
||||
> What happened to 0.6 and 0.7?
|
||||
|
||||
It's become increasingly obvious since our launch in May that people want to use React on the server. With the server-side rendering abilities, that's a perfect fit. However using the same copy of React on the server and then packaging it up for the client is surprisingly a harder problem. People have been using our `react-tools` module which includes React, but when browserifying that ends up packaging all of `esprima` and some other dependencies that aren't needed on the client. So we wanted to make this whole experience better.
|
||||
|
||||
We talked with [Jeff Barczewski][jeff] who was the owner of the `react` module on npm. He was kind enough to transition ownership to us and release his package under a different name: `autoflow`. I encourage you to [check it out][autoflow] if you're writing a lot of asynchronous code. In order to not break all of `react`'s current users of 0.7.x, we decided to bump our version to 0.8 and skip the issue entirely. We're also including a warning if you use our `react` module like you would use the previous package.
|
||||
|
||||
In order to make the transition to 0.8 for our current users as painless as possible, we decided to make 0.8 primarily a bug fix release on top of 0.5. No public APIs were changed (even if they were already marked as deprecated). We haven't added any of the new features we have in master, though we did take the opportunity to pull in some improvements to internals.
|
||||
|
||||
We hope that by releasing `react` on npm, we will enable a new set of uses that have been otherwise difficult. All feedback is welcome!
|
||||
|
||||
|
||||
## Changelog
|
||||
|
||||
### React
|
||||
|
||||
* Added support for more attributes:
|
||||
* `rows` & `cols` for `<textarea>`
|
||||
* `defer` & `async` for `<script>`
|
||||
* `loop` for `<audio>` & `<video>`
|
||||
* `autoCorrect` for form fields (a non-standard attribute only supported by mobile WebKit)
|
||||
* Improved error messages
|
||||
* Fixed Selection events in IE11
|
||||
* Added `onContextMenu` events
|
||||
|
||||
### React with Addons
|
||||
|
||||
* Fixed bugs with TransitionGroup when children were undefined
|
||||
* Added support for `onTransition`
|
||||
|
||||
### react-tools
|
||||
|
||||
* Upgraded `jstransform` and `esprima-fb`
|
||||
|
||||
### JSXTransformer
|
||||
|
||||
* Added support for use in IE8
|
||||
* Upgraded browserify, which reduced file size by ~65KB (16KB gzipped)
|
||||
|
||||
[jeff]: https://github.com/jeffbski
|
||||
[autoflow]: https://github.com/jeffbski/autoflow
|
||||
105
docs/_posts/2013-12-23-community-roundup-12.md
Normal file
105
docs/_posts/2013-12-23-community-roundup-12.md
Normal file
@@ -0,0 +1,105 @@
|
||||
---
|
||||
title: "Community Round-up #12"
|
||||
layout: post
|
||||
author: Vjeux
|
||||
---
|
||||
|
||||
React got featured on the front-page of Hacker News thanks to the Om library. If you try it out for the first time, take a look at the [docs](/react/docs/getting-started.html) and do not hesitate to ask questions on the [Google Group](http://groups.google.com/group/reactjs), [IRC](irc://chat.freenode.net/reactjs) or [Stack Overflow](http://stackoverflow.com/questions/tagged/reactjs). We are trying our best to help you out!
|
||||
|
||||
## The Future of Javascript MVC
|
||||
|
||||
[David Nolen](http://swannodette.github.io/) announced Om, a thin wrapper on-top of React in ClojureScript. It stands out by only using immutable data structures. This unlocks the ability to write a very efficient [shouldComponentUpdate](http://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate) and get huge performance improvements on some tasks.
|
||||
|
||||
> We've known this for some time over here in the ClojureScript corner of the world - all of our collections are immutable and modeled directly on the original Clojure versions written in Java. Modern JavaScript engines have now been tuned to the point that it's no longer uncommon to see collection performance within 2.5X of the Java Virtual Machine.
|
||||
>
|
||||
> Wait, wait, wait. What does the performance of persistent data structures have to do with the future of JavaScript MVCs?
|
||||
>
|
||||
> A whole lot.
|
||||
> <figure>[](http://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/)</figure>
|
||||
>
|
||||
> [Read the full article...](http://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/)
|
||||
|
||||
|
||||
|
||||
## Scroll Position with React
|
||||
|
||||
Managing the scroll position when new content is inserted is usually very tricky to get right. [Vjeux](http://blog.vjeux.com/) discovered that [componentWillUpdate](http://facebook.github.io/react/docs/component-specs.html#updating-componentwillupdate) and [componentDidUpdate](http://facebook.github.io/react/docs/component-specs.html#updating-componentdidupdate) were triggered exactly at the right time to manage the scroll position.
|
||||
|
||||
> We can check the scroll position before the component has updated with componentWillUpdate and scroll if necessary at componentDidUpdate
|
||||
>
|
||||
> ```
|
||||
componentWillUpdate: function() {
|
||||
var node = this.getDOMNode();
|
||||
this.shouldScrollBottom =
|
||||
(node.scrollTop + node.offsetHeight) === node.scrollHeight;
|
||||
},
|
||||
componentDidUpdate: function() {
|
||||
if (this.shouldScrollBottom) {
|
||||
var node = this.getDOMNode();
|
||||
node.scrollTop = node.scrollHeight
|
||||
}
|
||||
},
|
||||
```
|
||||
>
|
||||
> [Check out the blog article...](http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html)
|
||||
|
||||
|
||||
## Lights Out
|
||||
|
||||
React declarative approach is well suited to write games. [Cheng Lou](https://github.com/chenglou) wrote the famous Lights Out game in React. It's a good example of use of [TransitionGroup](http://facebook.github.io/react/docs/animation.html) to implement animations.
|
||||
<figure>[](http://chenglou.github.io/react-lights-out/)</figure>
|
||||
|
||||
[Try it out!](http://chenglou.github.io/react-lights-out/)
|
||||
|
||||
|
||||
## Reactive Table Bookmarklet
|
||||
|
||||
[Stoyan Stefanov](http://www.phpied.com/) wrote a bookmarklet to process tables on the internet. It adds a little "pop" button that expands to a full-screen view with sorting, editing and export to csv and json.
|
||||
<figure>[](http://www.phpied.com/reactivetable-bookmarklet/)</figure>
|
||||
|
||||
[Check out the blog post...](http://www.phpied.com/reactivetable-bookmarklet/)
|
||||
|
||||
|
||||
## MontageJS Tutorial in React
|
||||
|
||||
[Ross Allen](https://twitter.com/ssorallen) implemented [MontageJS](http://montagejs.org/)'s [Reddit tutorial](http://montagejs.org/docs/tutorial-reddit-client-with-montagejs.html) in React. This is a good opportunity to compare the philosophies of the two libraries.
|
||||
|
||||
<iframe width="100%" height="300" src="http://jsfiddle.net/ssorallen/fEsYt/embedded/result,html,js" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
|
||||
|
||||
[View the source on JSFiddle...](http://jsfiddle.net/ssorallen/fEsYt/)
|
||||
|
||||
## Writing Good React Components
|
||||
|
||||
[William Högman Rudenmalm](http://blog.whn.se/) wrote an article on how to write good React components. This is full of good advice.
|
||||
|
||||
> The idea of dividing software into smaller parts or components is hardly new - It is the essance of good software. The same principles that apply to software in general apply to building React components. That doesn’t mean that writing good React components is just about applying general rules.
|
||||
>
|
||||
> The web offers a unique set of challenges, which React offers interesting solutions to. First and foremost among these solutions is the what is called the Mock DOM. Rather than having user code interface with the DOM in a direct fashion, as is the case with most DOM manipulation libraries.
|
||||
>
|
||||
> You build a model of how you want the DOM end up like. React then inserts this model into the DOM. This is very useful for updates because React simply compares the model or mock DOM against the actual DOM, and then only updates based on the difference between the two states.
|
||||
>
|
||||
> [Read the full article ...](http://blog.whn.se/post/69621609605/writing-good-react-components)
|
||||
|
||||
|
||||
## Hoodie React TodoMVC
|
||||
|
||||
[Sven Lito](http://svenlito.com/) integrated the React TodoMVC example within an [Hoodie](http://hood.ie/) web app environment. This should let you get started using Hoodie and React.
|
||||
|
||||
```
|
||||
hoodie new todomvc -t "hoodiehq/hoodie-react-todomvc"
|
||||
```
|
||||
|
||||
[Check out on GitHub...](https://github.com/hoodiehq/hoodie-react-todomvc)
|
||||
|
||||
## JSX Compiler
|
||||
|
||||
Ever wanted to have a quick way to see what a JSX tag would be converted to? [Tim Yung](http://www.yungsters.com/) made a page for it.
|
||||
<figure>[](http://facebook.github.io/react/jsx-compiler.html)</figure>
|
||||
|
||||
[Try it out!](http://facebook.github.io/react/jsx-compiler.html)
|
||||
|
||||
|
||||
|
||||
## Random Tweet
|
||||
|
||||
<center><blockquote class="twitter-tweet" lang="en"><p>.<a href="https://twitter.com/jordwalke">@jordwalke</a> lays down some truth <a href="http://t.co/AXAn0UlUe3">http://t.co/AXAn0UlUe3</a>, optimizing your JS application shouldn't force you to rewrite so much code <a href="https://twitter.com/search?q=%23reactjs&src=hash">#reactjs</a></p>— David Nolen (@swannodette) <a href="https://twitter.com/swannodette/statuses/413780079249215488">December 19, 2013</a></blockquote></center>
|
||||
119
docs/_posts/2013-12-30-community-roundup-13.md
Normal file
119
docs/_posts/2013-12-30-community-roundup-13.md
Normal file
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: "Community Round-up #13"
|
||||
layout: post
|
||||
author: Vjeux
|
||||
---
|
||||
|
||||
Happy holidays! This blog post is a little-late Christmas present for all the React users. Hopefully it will inspire you to write awesome web apps in 2014!
|
||||
|
||||
|
||||
## React Touch
|
||||
|
||||
[Pete Hunt](http://www.petehunt.net/) wrote three demos showing that React can be used to run 60fps native-like experiences on mobile web. A frosted glass effect, an image gallery with 3d animations and an infinite scroll view.
|
||||
|
||||
<figure><iframe src="//player.vimeo.com/video/79659941" width="220" height="400" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></figure>
|
||||
|
||||
[Try out the demos!](http://petehunt.github.io/react-touch/)
|
||||
|
||||
|
||||
## Introduction to React
|
||||
|
||||
[Stoyan Stefanov](http://www.phpied.com/) talked at Joe Dev On Tech about React. He goes over all the features of the library and ends with a concrete example.
|
||||
|
||||
<figure><iframe width="560" height="315" src="//www.youtube.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe></figure>
|
||||
|
||||
|
||||
## JSX: E4X The Good Parts
|
||||
|
||||
JSX is often compared to the now defunct E4X, [Vjeux](http://blog.vjeux.com/) went over all the E4X features and explained how JSX is different and hopefully doesn't repeat the same mistakes.
|
||||
|
||||
> E4X (ECMAScript for XML) is a Javascript syntax extension and a runtime to manipulate XML. It was promoted by Mozilla but failed to become mainstream and is now deprecated. JSX was inspired by E4X. In this article, I'm going to go over all the features of E4X and explain the design decisions behind JSX.
|
||||
>
|
||||
> **Historical Context**
|
||||
>
|
||||
> E4X has been created in 2002 by John Schneider. This was the golden age of XML where it was being used for everything: data, configuration files, code, interfaces (DOM) ... E4X was first implemented inside of Rhino, a Javascript implementation from Mozilla written in Java.
|
||||
>
|
||||
> [Continue reading ...](http://blog.vjeux.com/2013/javascript/jsx-e4x-the-good-parts.html)
|
||||
|
||||
|
||||
## React + Socket.io
|
||||
|
||||
[Geert Pasteels](http://enome.be/nl) made a small experiment with Socket.io. He wrote a very small mixin that synchronizes React state with the server. Just include this mixin to your React component and it is now live!
|
||||
|
||||
```javascript
|
||||
changeHandler: function (data) {
|
||||
if (!_.isEqual(data.state, this.state) && this.path === data.path) {
|
||||
this.setState(data.state);
|
||||
}
|
||||
},
|
||||
componentDidMount: function (root) {
|
||||
this.path = utils.nodePath(root);
|
||||
socket.on('component-change', this.changeHandler);
|
||||
},
|
||||
componentWillUpdate: function (props, state) {
|
||||
socket.emit('component-change', { path: this.path, state: state });
|
||||
},
|
||||
componentWillUnmount: function () {
|
||||
socket.removeListener('component-change', this.change);
|
||||
}
|
||||
```
|
||||
|
||||
[Check it out on GitHub...](https://github.com/Enome/react.io)
|
||||
|
||||
|
||||
## cssobjectify
|
||||
|
||||
[Andrey Popp](http://andreypopp.com/) implemented a source transform that takes a CSS file and converts it to JSON. This integrates pretty nicely with React.
|
||||
|
||||
```javascript
|
||||
/* style.css */
|
||||
MyComponent {
|
||||
font-size: 12px;
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
/* myapp.js */
|
||||
var React = require('react-tools/build/modules/React');
|
||||
var Styles = require('./styles.css');
|
||||
|
||||
var MyComponent = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div style={Styles.MyComponent}>
|
||||
Hello, world!
|
||||
</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
[Check it out on GitHub...](https://github.com/andreypopp/cssobjectify)
|
||||
|
||||
|
||||
## ngReact
|
||||
|
||||
[David Chang](http://davidandsuzi.com/) working at [HasOffer](http://www.hasoffers.com/) wanted to speed up his Angular app and replaced Angular primitives by React at different layers. When using React naively it is 67% faster, but when combining it with angular's transclusion it is 450% slower.
|
||||
|
||||
> Rendering this takes 803ms for 10 iterations, hovering around 35 and 55ms for each data reload (that's 67% faster). You'll notice that the first load takes a little longer than successive loads, and the second load REALLY struggles - here, it's 433ms, which is more than half of the total time!
|
||||
> <figure>[](http://davidandsuzi.com/ngreact-react-components-in-angular/)</figure>
|
||||
>
|
||||
> [Read the full article...](http://davidandsuzi.com/ngreact-react-components-in-angular/)
|
||||
|
||||
|
||||
## vim-jsx
|
||||
|
||||
[Max Wang](https://github.com/mxw) made a vim syntax highlighting and indentation plugin for vim.
|
||||
|
||||
> Syntax highlighting and indenting for JSX. JSX is a JavaScript syntax transformer which translates inline XML document fragments into JavaScript objects. It was developed by Facebook alongside React.
|
||||
>
|
||||
> This bundle requires pangloss's [vim-javascript](https://github.com/pangloss/vim-javascript) syntax highlighting.
|
||||
>
|
||||
> Vim support for inline XML in JS is remarkably similar to the same for PHP.
|
||||
>
|
||||
> [View on GitHub...](https://github.com/mxw/vim-jsx)
|
||||
|
||||
|
||||
## Random Tweet
|
||||
|
||||
<center><blockquote class="twitter-tweet" lang="en"><p>I may be starting to get annoying with this, but ReactJS is really exciting. I truly feel the virtual DOM is a game changer.</p>— Eric Florenzano (@ericflo) <a href="https://twitter.com/ericflo/statuses/413842834974732288">December 20, 2013</a></blockquote></center>
|
||||
|
||||
19
docs/_posts/2014-01-02-react-chrome-developer-tools.md
Normal file
19
docs/_posts/2014-01-02-react-chrome-developer-tools.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: "React Chrome Developer Tools"
|
||||
layout: post
|
||||
author: Sebastian Markbåge
|
||||
---
|
||||
|
||||
With the new year, we thought you'd enjoy some new tools for debugging React code. Today we're releasing the [React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi), an extension to the Chrome Developer Tools. [Download them from the Chrome Web Store](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi).
|
||||
|
||||
<figure><iframe width="560" height="315" src="//www.youtube.com/embed/Cey7BS6dE0M" frameborder="0" allowfullscreen></iframe></figure>
|
||||
|
||||
You will get a new tab titled "React" in your Chrome DevTools. This tab shows you a list of the root React Components that are rendered on the page as well as the subcomponents that each root renders.
|
||||
|
||||
Selecting a Component in this tab allows you to view and edit its props and state in the panel on the right. In the breadcrumbs at the bottom, you can inspect the selected Component, the Component that created it, the Component that created that one, and so on.
|
||||
|
||||
When you inspect a DOM element using the regular Elements tab, you can switch over to the React tab and the corresponding Component will be automatically selected. The Component will also be automatically selected if you have a breakpoint within its render phase. This allows you to step through the render tree and see how one Component affects another one.
|
||||
<figure>[](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi)</figure>
|
||||
|
||||
We hope these tools will help your team better understand your component hierarchy and track down bugs. We're very excited about this initial launch and appreciate any feedback you may have. As always, we also accept [pull requests on GitHub](https://github.com/facebook/react-devtools).
|
||||
|
||||
92
docs/_posts/2014-01-06-community-roundup-14.md
Normal file
92
docs/_posts/2014-01-06-community-roundup-14.md
Normal file
@@ -0,0 +1,92 @@
|
||||
---
|
||||
title: "Community Round-up #14"
|
||||
layout: post
|
||||
author: Vjeux
|
||||
---
|
||||
|
||||
The theme of this first round-up of 2014 is integration. I've tried to assemble a list of articles and projects that use React in various environments.
|
||||
|
||||
## React Baseline
|
||||
|
||||
React is only one-piece of your web application stack. [Mark Lussier](https://github.com/intabulas) shared his baseline stack that uses React along with Grunt, Browserify, Bower, Zepto, Director and Sass. This should help you get started using React for a new project.
|
||||
|
||||
> As I do more projects with ReactJS I started to extract a baseline to use when starting new projects. This is very opinionated and I change my opinion from time to time. This is by no ways perfect and in your opinion most likely wrong :).. which is why I love github
|
||||
>
|
||||
> I encourage you to fork, and make it right and submit a pull request!
|
||||
>
|
||||
> My current opinion is using tools like Grunt, Browserify, Bower and mutiple grunt plugins to get the job done. I also opted for Zepto over jQuery and the Flatiron Project's Director when I need a router. Oh and for the last little bit of tech that makes you mad, I am in the SASS camp when it comes to stylesheets
|
||||
>
|
||||
> [Check it out on GitHub...](https://github.com/intabulas/reactjs-baseline)
|
||||
|
||||
|
||||
## Animal Sounds
|
||||
|
||||
[Josh Duck](http://joshduck.com/) used React in order to build a Windows 8 tablet app. This is a good example of a touch app written in React.
|
||||
<figure>[](http://apps.microsoft.com/windows/en-us/app/baby-play-animal-sounds/9280825c-2ed9-41c0-ba38-aa9a5b890bb9)</figure>
|
||||
|
||||
[Download the app...](http://apps.microsoft.com/windows/en-us/app/baby-play-animal-sounds/9280825c-2ed9-41c0-ba38-aa9a5b890bb9)
|
||||
|
||||
|
||||
## React Rails Tutorial
|
||||
|
||||
[Selem Delul](http://selem.im) bundled the [React Tutorial](http://facebook.github.io/react/docs/tutorial.html) into a rails app. This is a good example on how to get started with a rails project.
|
||||
|
||||
> ```
|
||||
git clone https://github.com/necrodome/react-rails-tutorial
|
||||
cd react-rails-tutorial
|
||||
bundle install
|
||||
rake db:migrate
|
||||
rails s
|
||||
```
|
||||
> Then visit http://localhost:3000/app to see the React application that is explained in the React Tutorial. Try opening multiple tabs!
|
||||
>
|
||||
> [View on GitHub...](https://github.com/necrodome/react-rails-tutorial)
|
||||
|
||||
## Mixing with Backbone
|
||||
|
||||
[Eldar Djafarov](http://eldar.djafarov.com/) implemented a mixin to link Backbone models to React state and a small abstraction to write two-way binding on-top.
|
||||
|
||||
<iframe width="100%" height="300" src="http://jsfiddle.net/djkojb/qZf48/13/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
|
||||
|
||||
[Check out the blog post...](http://eldar.djafarov.com/2013/11/reactjs-mixing-with-backbone/)
|
||||
|
||||
|
||||
## React Infinite Scroll
|
||||
|
||||
[Guillaume Rivals](https://twitter.com/guillaumervls) implemented an InfiniteScroll component. This is a good example of a React component that has a simple yet powerful API.
|
||||
|
||||
```javascript
|
||||
<InfiniteScroll
|
||||
pageStart={0}
|
||||
loadMore={loadFunc}
|
||||
hasMore={true || false}
|
||||
loader={<div className="loader">Loading ...</div>}>
|
||||
{items} // <-- This is the "stuff" you want to load
|
||||
</InfiniteScroll>
|
||||
```
|
||||
|
||||
[Try it out on GitHub!](https://github.com/guillaumervls/react-infinite-scroll)
|
||||
|
||||
|
||||
## Web Components Style
|
||||
|
||||
[Thomas Aylott](http://subtlegradient.com/) implemented an API that looks like Web Components but using React underneath.
|
||||
|
||||
<iframe width="100%" height="300" src="http://jsfiddle.net/SubtleGradient/ue2Aa/embedded/html,js,result" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
|
||||
|
||||
|
||||
## React vs Angular
|
||||
|
||||
React is often compared with Angular. [Pete Hunt](http://skulbuny.com/2013/10/31/react-vs-angular/) wrote an opinionated post on the subject.
|
||||
|
||||
> First of all I think it’s important to evaluate technologies on objective rather than subjective features. “It feels nicer” or “it’s cleaner” aren’t valid reasons: performance, modularity, community size and ease of testing / integration with other tools are.
|
||||
>
|
||||
> I’ve done a lot of work benchmarking, building apps, and reading the code of Angular to try to come up with a reasonable comparison between their ways of doing things.
|
||||
>
|
||||
> [Read the full post...](http://skulbuny.com/2013/10/31/react-vs-angular/)
|
||||
|
||||
|
||||
|
||||
## Random Tweet
|
||||
|
||||
<div><blockquote class="twitter-tweet" lang="en"><p>Really intrigued by React.js. I've looked at all JS frameworks, and excepting <a href="https://twitter.com/serenadejs">@serenadejs</a> this is the first one which makes sense to me.</p>— Jonas Nicklas (@jonicklas) <a href="https://twitter.com/jonicklas/statuses/412640708755869696">December 16, 2013</a></blockquote></div>
|
||||
126
docs/_posts/2014-02-05-community-roundup-15.md
Normal file
126
docs/_posts/2014-02-05-community-roundup-15.md
Normal file
@@ -0,0 +1,126 @@
|
||||
---
|
||||
title: "Community Round-up #15"
|
||||
layout: post
|
||||
author: Jonas Gebhardt
|
||||
---
|
||||
|
||||
Interest in React seems to have surged ever since David Nolen ([@swannodette](https://twitter.com/swannodette))'s introduction of [Om](https://github.com/swannodette/om) in his post ["The Future of Javascript MVC Frameworks"](http://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/).
|
||||
|
||||
In this React Community Round-up, we are taking a closer look at React from a functional programming perspective.
|
||||
|
||||
## "React: Another Level of Indirection"
|
||||
To start things off, Eric Normand ([@ericnormand](https://twitter.com/ericnormand)) of [LispCast](http://lispcast.com) makes the case for [React from a general functional programming standpoint](http://www.lispcast.com/react-another-level-of-indirection) and explains how React's "Virtual DOM provides the last piece of the Web Frontend Puzzle for ClojureScript".
|
||||
|
||||
> The Virtual DOM is an indirection mechanism that solves the difficult problem of DOM programming: how to deal with incremental changes to a stateful tree structure. By abstracting away the statefulness, the Virtual DOM turns the real DOM into an immediate mode GUI, which is perfect for functional programming.
|
||||
>
|
||||
> [Read the full post...](http://www.lispcast.com/react-another-level-of-indirection)
|
||||
|
||||
## Reagent: Minimalistic React for ClojureScript
|
||||
Dan Holmsand ([@holmsand](https://twitter.com/holmsand)) created [Reagent](http://holmsand.github.io/reagent/), a simplistic ClojureScript API to React.
|
||||
|
||||
> It allows you to define efficient React components using nothing but plain ClojureScript functions and data, that describe your UI using a Hiccup-like syntax.
|
||||
>
|
||||
> The goal of Reagent is to make it possible to define arbitrarily complex UIs using just a couple of basic concepts, and to be fast enough by default that you rarely have to care about performance.
|
||||
>
|
||||
> [Check it out on Github...](http://holmsand.github.io/reagent/)
|
||||
|
||||
|
||||
## Functional DOM programming
|
||||
|
||||
React's one-way data-binding naturally lends itself to a functional programming approach. Facebook's Pete Hunt ([@floydophone](https://twitter.com/floydophone)) explores how one would go about [writing web apps in a functional manner](https://medium.com/p/67d81637d43). Spoiler alert:
|
||||
|
||||
> This is React. It’s not about templates, or data binding, or DOM manipulation. It’s about using functional programming with a virtual DOM representation to build ambitious, high-performance apps with JavaScript.
|
||||
>
|
||||
> [Read the full post...](https://medium.com/p/67d81637d43)
|
||||
|
||||
Pete also explains this in detail at his #MeteorDevShop talk (about 30 Minutes):
|
||||
|
||||
<iframe width="560" height="315" src="//www.youtube.com/embed/Lqcs6hPOcFw?start=2963" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
|
||||
|
||||
## Kioo: Separating markup and logic
|
||||
[Creighton Kirkendall](https://github.com/ckirkendall) created [Kioo](https://github.com/ckirkendall/kioo), which adds Enlive-style templating to React. HTML templates are separated from the application logic. Kioo comes with separate examples for both Om and Reagent.
|
||||
|
||||
A basic example from github:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<header>
|
||||
<h1>Header placeholder</h1>
|
||||
<ul id="navigation">
|
||||
<li class="nav-item"><a href="#">Placeholder</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
<div class="content">place holder</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```clojure
|
||||
...
|
||||
|
||||
(defn my-nav-item [[caption func]]
|
||||
(kioo/component "main.html" [:.nav-item]
|
||||
{[:a] (do-> (content caption)
|
||||
(set-attr :onClick func))}))
|
||||
|
||||
(defn my-header [heading nav-elms]
|
||||
(kioo/component "main.html" [:header]
|
||||
{[:h1] (content heading)
|
||||
[:ul] (content (map my-nav-item nav-elms))}))
|
||||
|
||||
(defn my-page [data]
|
||||
(kioo/component "main.html"
|
||||
{[:header] (substitute (my-header (:heading data)
|
||||
(:navigation data)))
|
||||
[:.content] (content (:content data))}))
|
||||
|
||||
(def app-state (atom {:heading "main"
|
||||
:content "Hello World"
|
||||
:navigation [["home" #(js/alert %)]
|
||||
["next" #(js/alert %)]]}))
|
||||
|
||||
(om/root app-state my-page (.-body js/document))
|
||||
```
|
||||
|
||||
## Om
|
||||
|
||||
In an interview with David Nolen, Tom Coupland ([@tcoupland](https://twitter.com/tcoupland)) of InfoQ provides a nice summary of recent developments around Om ("[Om: Enhancing Facebook's React with Immutability](http://www.infoq.com/news/2014/01/om-react)").
|
||||
|
||||
> David [Nolen]: I think people are starting to see the limitations of just JavaScript and jQuery and even more structured solutions like Backbone, Angular, Ember, etc. React is a fresh approach to the DOM problem that seems obvious in hindsight.
|
||||
>
|
||||
> [Read the full interview...](http://www.infoq.com/news/2014/01/om-react)
|
||||
|
||||
### A slice of React, ClojureScript and Om
|
||||
|
||||
Fredrik Dyrkell ([@lexicallyscoped](https://twitter.com/lexicallyscoped)) rewrote part of the [React tutorial in both ClojureScript and Om](http://www.lexicallyscoped.com/2013/12/25/slice-of-reactjs-and-cljs.html), along with short, helpful explanations.
|
||||
|
||||
> React has sparked a lot of interest in the Clojure community lately [...]. At the very core, React lets you build up your DOM representation in a functional fashion by composing pure functions and you have a simple building block for everything: React components.
|
||||
>
|
||||
> [Read the full post...](http://www.lexicallyscoped.com/2013/12/25/slice-of-reactjs-and-cljs.html)
|
||||
|
||||
In a separate post, Dyrkell breaks down [how to build a binary clock component](http://www.lexicallyscoped.com/2014/01/23/ClojureScript-react-om-binary-clock.html) in Om.
|
||||
|
||||
[[Demo](http://www.lexicallyscoped.com/demo/binclock/)] [[Code](https://github.com/fredyr/binclock/blob/master/src/binclock/core.cljs)]
|
||||
|
||||
### Time Travel: Implementing undo in Om
|
||||
David Nolen shows how to leverage immutable data structures to [add global undo](http://swannodette.github.io/2013/12/31/time-travel/) functionality to an app – using just 13 lines of ClojureScript.
|
||||
|
||||
### A Step-by-Step Om Walkthrough
|
||||
|
||||
[Josh Lehman](http://www.joshlehman.me) took the time to create an extensive [step-by-step walkthrough](http://www.joshlehman.me/rewriting-the-react-tutorial-in-om/) of the React tutorial in Om. The well-documented source is on [github](https://github.com/jalehman/omtut-starter).
|
||||
|
||||
### Omkara
|
||||
|
||||
[brendanyounger](https://github.com/brendanyounger) created [omkara](https://github.com/brendanyounger/omkara), a starting point for ClojureScript web apps based on Om/React. It aims to take advantage of server-side rendering and comes with a few tips on getting started with Om/React projects.
|
||||
|
||||
### Om Experience Report
|
||||
Adam Solove ([@asolove](https://twitter.com/asolove/)) [dives a little deeper into Om, React and ClojureScript](http://adamsolove.com/js/clojure/2014/01/06/om-experience-report.html). He shares some helpful tips he gathered while building his [CartoCrayon](https://github.com/asolove/carto-crayon) prototype.
|
||||
|
||||
## Not-so-random Tweet
|
||||
|
||||
|
||||
<div><blockquote class="twitter-tweet" lang="en"><p>[@swannodette](https://twitter.com/swannodette) No thank you! It's honestly a bit weird because Om is exactly what I didn't know I wanted for doing functional UI work.</p>— Adam Solove (@asolove) <a href="https://twitter.com/asolove/status/420294067637858304">January 6, 2014</a></blockquote></div>
|
||||
86
docs/_posts/2014-02-15-community-roundup-16.md
Normal file
86
docs/_posts/2014-02-15-community-roundup-16.md
Normal file
@@ -0,0 +1,86 @@
|
||||
---
|
||||
title: "Community Round-up #16"
|
||||
layout: post
|
||||
author: Jonas Gebhardt
|
||||
---
|
||||
|
||||
There have been many posts recently covering the <i>why</i> and <i>how</i> of React. This week's community round-up includes a collection of recent articles to help you get started with React, along with a few posts that explain some of the inner workings.
|
||||
|
||||
|
||||
## React in a nutshell
|
||||
Got five minutes to pitch React to your coworkers? John Lynch ([@johnrlynch](https://twitter.com/johnrlynch)) put together [this excellent and refreshing slideshow](http://slid.es/johnlynch/reactjs):
|
||||
|
||||
<iframe src="//slid.es/johnlynch/reactjs/embed" width="576" height="420" scrolling="no" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||
|
||||
|
||||
|
||||
## React's diff algorithm
|
||||
|
||||
React core team member Christopher Chedeau ([@vjeux](https://twitter.com/vjeux)) explores the innards of React's tree diffing algorithm in this [extensive and well-illustrated post](http://calendar.perfplanet.com/2013/diff/). <figure>[](http://calendar.perfplanet.com/2013/diff/)</figure>
|
||||
|
||||
While we're talking about tree diffing: Matt Esch ([@MatthewEsch](https://twitter.com/MatthewEsch)) created [this project](https://github.com/Matt-Esch/virtual-dom), which aims to implement the virtual DOM and a corresponding diff algorithm as separate modules.
|
||||
|
||||
|
||||
|
||||
|
||||
## Many, many new introductions to React!
|
||||
|
||||
|
||||
|
||||
James Padosley wrote a short post on the basics (and merits) of React: [What is React?](http://james.padolsey.com/javascript/what-is-react/)
|
||||
> What I like most about React is that it doesn't impose heady design patterns and data-modelling abstractions on me. [...] Its opinions are so minimal and its abstractions so focused on the problem of the DOM, that you can merrily slap your design choices atop.
|
||||
|
||||
> [Read the full post...](http://james.padolsey.com/javascript/what-is-react/)
|
||||
|
||||
Taylor Lapeyre ([@taylorlapeyre](https://twitter.com/taylorlapeyre)) wrote another nice [introduction to React](http://words.taylorlapeyre.me/an-introduction-to-react).
|
||||
|
||||
> React expects you to do the work of getting and pushing data from the server. This makes it very easy to implement React as a front end solution, since it simply expects you to hand it data. React does all the other work.
|
||||
|
||||
> [Read the full post...](http://words.taylorlapeyre.me/an-introduction-to-react)
|
||||
|
||||
|
||||
[This "Deep explanation for newbies"](http://www.webdesignporto.com/react-js-in-pure-javascript-facebook-library/?utm_source=echojs&utm_medium=post&utm_campaign=echojs) by [@ProJavaScript](https://twitter.com/ProJavaScript) explains how to get started building a React game without using the optional JSX syntax.
|
||||
|
||||
### React around the world
|
||||
|
||||
It's great to see the React community expand internationally. [This site](http://habrahabr.ru/post/189230/) features a React introduction in Russian.
|
||||
|
||||
### React tutorial series
|
||||
|
||||
[Christopher Pitt](https://medium.com/@followchrisp) explains [React Components](https://medium.com/react-tutorials/828c397e3dc8) and [React Properties](https://medium.com/react-tutorials/ef11cd55caa0). The former includes a nice introduction to using JSX, while the latter focuses on adding interactivity and linking multiple components together. Also check out the [other posts in his React Tutorial series](https://medium.com/react-tutorials), e.g. on using [React + Backbone Model](https://medium.com/react-tutorials/8aaec65a546c) and [React + Backbone Router](https://medium.com/react-tutorials/c00be0cf1592).
|
||||
|
||||
### Beginner tutorial: Implementing the board game Go
|
||||
|
||||
[Chris LaRose](http://cjlarose.com/) walks through the steps of creating a Go app in React, showing how to separate application logic from the rendered components. Check out his [tutorial](http://cjlarose.com/2014/01/09/react-board-game-tutorial.html) or go straight to the [code](https://github.com/cjlarose/react-go).
|
||||
|
||||
### Egghead.io video tutorials
|
||||
|
||||
Joe Maddalone ([@joemaddalone](https://twitter.com/joemaddalone)) of [egghead.io](https://egghead.io/) created a series of React video tutorials, such as [this](http://www.youtube.com/watch?v=rFvZydtmsxM&feature=youtu.be&a) introduction to React Components. [[part 1](http://www.youtube.com/watch?v=rFvZydtmsxM&feature=youtu.be&a)], [[part 2](http://www.youtube.com/watch?v=5yvFLrt7N8M)]
|
||||
|
||||
### "React: Finally, a great server/client web stack"
|
||||
|
||||
Eric Florenzano ([@ericflo](https://twitter.com/ericflo)) sheds some light on what makes React perfect for server rendering:
|
||||
|
||||
> [...] the ideal solution would fully render the markup on the server, deliver it to the client so that it can be shown to the user instantly. Then it would asynchronously load some Javascript that would attach to the rendered markup, and invisibly promote the page into a full app that can render its own markup. [...]
|
||||
|
||||
> What I've discovered is that enough of the pieces have come together, that this futuristic-sounding web environment is actually surprisingly easy to do now with React.js.
|
||||
|
||||
> [Read the full post...](http://eflorenzano.com/blog/2014/01/23/react-finally-server-client/)
|
||||
|
||||
## Building a complex React component
|
||||
[Matt Harrison](http://matt-harrison.com/) walks through the process of [creating an SVG-based Resistance Calculator](http://matt-harrison.com/building-a-complex-web-component-with-facebooks-react-library/) using React. <figure>[](http://matt-harrison.com/building-a-complex-web-component-with-facebooks-react-library/)</figure>
|
||||
|
||||
|
||||
|
||||
## Random Tweets
|
||||
|
||||
<div><blockquote class="twitter-tweet" lang="en"><p>[#reactjs](https://twitter.com/search?q=%23reactjs&src=hash) has very simple API, but it's amazing how much work has been done under the hood to make it blazing fast.</p>— Anton Astashov (@anton_astashov) <a href="https://twitter.com/anton_astashov/status/417556491646693378">December 30, 2013</a></blockquote></div>
|
||||
|
||||
<div><blockquote class="twitter-tweet" lang="en"><p>[#reactjs]((https://twitter.com/search?q=%23reactjs&src=hash) makes refactoring your HTML as easy & natural as refactoring your javascript [@react_js](https://twitter.com/react_js)</p>— Jared Forsyth (@jaredforsyth) <a href="https://twitter.com/jaredforsyth/status/420304083010854912">January 6, 2014</a></blockquote></div>
|
||||
|
||||
<div><blockquote class="twitter-tweet" lang="en"><p>Played with react.js for an hour, so many things suddenly became stupidly simple.</p>— andrewingram (@andrewingram) <a href="https://twitter.com/andrewingram/status/422810480701620225">January 13, 2014</a></blockquote></div>
|
||||
|
||||
<div><blockquote class="twitter-tweet" lang="en"><p>[@okonetchnikov](https://twitter.com/okonetchnikov) HOLY CRAP react is nice</p>— julik (@julikt) <a href="https://twitter.com/julikt/status/422843478792765440">January 13, 2014</a></blockquote></div>
|
||||
|
||||
<div><blockquote class="twitter-tweet" lang="en"><p>brb rewriting everything with react
|
||||
</p>— Ben Smithett (@bensmithett) <a href="https://twitter.com/bensmithett/status/430671242186592256">February 4, 2014</a></blockquote></div>
|
||||
133
docs/_posts/2014-02-16-react-v0.9-rc1.md
Normal file
133
docs/_posts/2014-02-16-react-v0.9-rc1.md
Normal file
@@ -0,0 +1,133 @@
|
||||
---
|
||||
title: React v0.9 RC
|
||||
layout: post
|
||||
author: Ben Alpert
|
||||
---
|
||||
|
||||
We're almost ready to release React v0.9! We're posting a release candidate so that you can test your apps on it; we'd much prefer to find show-stopping bugs now rather than after we release.
|
||||
|
||||
The release candidate is available for download from the CDN:
|
||||
|
||||
* **React**
|
||||
Dev build with warnings: <http://fb.me/react-0.9.0-rc1.js>
|
||||
Minified build for production: <http://fb.me/react-0.9.0-rc1.min.js>
|
||||
* **React with Add-Ons**
|
||||
Dev build with warnings: <http://fb.me/react-with-addons-0.9.0-rc1.js>
|
||||
Minified build for production: <http://fb.me/react-with-addons-0.9.0-rc1.min.js>
|
||||
* **In-Browser JSX transformer**
|
||||
<http://fb.me/JSXTransformer-0.9.0-rc1.js>
|
||||
|
||||
We've also published version `0.9.0-rc1` of the `react` and `react-tools` packages on npm and the `react` package on bower.
|
||||
|
||||
Please try these builds out and [file an issue on GitHub](https://github.com/facebook/react/issues/new) if you see anything awry.
|
||||
|
||||
## Upgrade Notes
|
||||
|
||||
In addition to the changes to React core listed below, we've made a small change to the way JSX interprets whitespace to make things more consistent. With this release, space between two components on the same line will be preserved, while a newline separating a text node from a tag will be eliminated in the output. Consider the code:
|
||||
|
||||
```html
|
||||
<div>
|
||||
Monkeys:
|
||||
{listOfMonkeys} {submitButton}
|
||||
</div>
|
||||
```
|
||||
|
||||
In v0.8 and below, it was transformed to the following:
|
||||
|
||||
```javascript
|
||||
React.DOM.div(null,
|
||||
" Monkeys: ",
|
||||
listOfMonkeys, submitButton
|
||||
)
|
||||
```
|
||||
|
||||
In v0.9, it will be transformed to this JS instead:
|
||||
|
||||
```javascript{2,3}
|
||||
React.DOM.div(null,
|
||||
"Monkeys:",
|
||||
listOfMonkeys, " ", submitButton
|
||||
)
|
||||
```
|
||||
|
||||
We believe this new behavior is more helpful and elimates cases where unwanted whitespace was previously added.
|
||||
|
||||
In cases where you want to preserve the space adjacent to a newline, you can write a JS string like `{"Monkeys: "}` in your JSX source. We've included a script to do an automated codemod of your JSX source tree that preserves the old whitespace behavior by adding and removing spaces appropriately. You can [install jsx\_whitespace\_transformer from npm](https://github.com/facebook/react/blob/master/npm-jsx_whitespace_transformer/README.md) and run it over your source tree to modify files in place. The transformed JSX files will preserve your code's existing whitespace behavior.
|
||||
|
||||
## Changelog
|
||||
|
||||
### React Core
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
- The lifecycle methods `componentDidMount` and `componentDidUpdate` no longer receive the root node as a parameter; use `this.getDOMNode()` instead
|
||||
- Whenever a prop is equal to `undefined`, the default value returned by `getDefaultProps` will now be used instead
|
||||
- `React.unmountAndReleaseReactRootNode` was previously deprecated and has now been removed
|
||||
- `React.renderComponentToString` is now synchronous and returns the generated HTML string
|
||||
- Full-page rendering (that is, rendering the `<html>` tag using React) is now supported only when starting with server-rendered markup
|
||||
- On mouse wheel events, `deltaY` is no longer negated
|
||||
- When prop types validation fails, a warning is logged instead of an error thrown (with the production build of React, the type checks are now skipped for performance)
|
||||
- On `input`, `select`, and `textarea` elements, `.getValue()` is no longer supported; use `.getDOMNode().value` instead
|
||||
- `this.context` on components is now reserved for internal use by React
|
||||
|
||||
#### New Features
|
||||
|
||||
- React now never rethrows errors, so stack traces are more accurate and Chrome's purple break-on-error stop sign now works properly
|
||||
- Added a new tool for profiling React components and identifying places where defining `shouldComponentUpdate` can give performance improvements
|
||||
- Added support for SVG tags `defs`, `linearGradient`, `polygon`, `radialGradient`, `stop`
|
||||
- Added support for more attributes:
|
||||
- `noValidate` and `formNoValidate` for forms
|
||||
- `property` for Open Graph `<meta>` tags
|
||||
- `sandbox`, `seamless`, and `srcDoc` for `<iframe>` tags
|
||||
- `scope` for screen readers
|
||||
- `span` for `<colgroup>` tags
|
||||
- Added support for defining `propTypes` in mixins
|
||||
- Added `any`, `arrayOf`, `component`, `oneOfType`, `renderable`, `shape` to `React.PropTypes`
|
||||
- Added support for `statics` on component spec for static component methods
|
||||
- On all events, `.currentTarget` is now properly set
|
||||
- On keyboard events, `.key` is now polyfilled in all browsers for special (non-printable) keys
|
||||
- On clipboard events, `.clipboardData` is now polyfilled in IE
|
||||
- On drag events, `.dataTransfer` is now present
|
||||
- Added support for `onMouseOver` and `onMouseOut` in addition to the existing `onMouseEnter` and `onMouseLeave` events
|
||||
- Added support for `onLoad` and `onError` on `<img>` elements
|
||||
- Added support for `onReset` on `<form>` elements
|
||||
- The `autoFocus` attribute is now polyfilled consistently on `input`, `select`, and `textarea`
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
- React no longer adds an `__owner__` property to each component's `props` object; passed-in props are now never mutated
|
||||
- When nesting top-level components (e.g., calling `React.renderComponent` within `componentDidMount`), events now properly bubble to the parent component
|
||||
- Fixed a case where nesting top-level components would throw an error when updating
|
||||
- Passing an invalid or misspelled propTypes type now throws an error
|
||||
- On mouse enter/leave events, `.target`, `.relatedTarget`, and `.type` are now set properly
|
||||
- On composition events, `.data` is now properly normalized in IE9 and IE10
|
||||
- CSS property values no longer have `px` appended for the unitless properties `columnCount`, `flex`, `flexGrow`, `flexShrink`, `lineClamp`, `order`, `widows`
|
||||
- Fixed a memory leak when unmounting children with a `componentWillUnmount` handler
|
||||
- Fixed a memory leak when `renderComponentToString` would store event handlers
|
||||
- Fixed an error that could be thrown when removing form elements during a click handler
|
||||
- `key` values containing `.` are now supported
|
||||
- Shortened `data-reactid` values for performance
|
||||
- Components now always remount when the `key` property changes
|
||||
- Event handlers are attached to `document` only when necessary, improving performance in some cases
|
||||
- Events no longer use `.returnValue` in modern browsers, eliminating a warning in Chrome
|
||||
- `scrollLeft` and `scrollTop` are no longer accessed on document.body, eliminating a warning in Chrome
|
||||
- General performance fixes, memory optimizations, improvements to warnings and error messages
|
||||
|
||||
### React with Addons
|
||||
|
||||
- `React.addons.TransitionGroup` was renamed to `React.addons.CSSTransitionGroup`
|
||||
- `React.addons.TransitionGroup` was added as a more general animation wrapper
|
||||
- `React.addons.cloneWithProps` was added for cloning components and modifying their props
|
||||
- Bug fix for adding back nodes during an exit transition for CSSTransitionGroup
|
||||
- Bug fix for changing `transitionLeave` in CSSTransitionGroup
|
||||
- Performance optimizations for CSSTransitionGroup
|
||||
- On checkbox `<input>` elements, `checkedLink` is now supported for two-way binding
|
||||
|
||||
### JSX Compiler and react-tools Package
|
||||
|
||||
- Whitespace normalization has changed; now space between two tags on the same line will be preserved, while newlines between two tags will be removed
|
||||
- The `react-tools` npm package no longer includes the React core libraries; use the `react` package instead.
|
||||
- `displayName` is now added in more cases, improving error messages and names in the React Dev Tools
|
||||
- Fixed an issue where an invalid token error was thrown after a JSX closing tag
|
||||
- `JSXTransformer` now uses source maps automatically in modern browsers
|
||||
- `JSXTransformer` error messages now include the filename and problematic line contents when a file fails to parse
|
||||
145
docs/_posts/2014-02-20-react-v0.9.md
Normal file
145
docs/_posts/2014-02-20-react-v0.9.md
Normal file
@@ -0,0 +1,145 @@
|
||||
---
|
||||
title: React v0.9
|
||||
layout: post
|
||||
author: Ben Alpert
|
||||
---
|
||||
|
||||
I'm excited to announce that today we're releasing React v0.9, which incorporates many bug fixes and several new features since the last release. This release contains almost four months of work, including over 800 commits from over 70 committers!
|
||||
|
||||
Thanks to everyone who tested the release candidate; we were able to find and fix an error in the event handling code, we upgraded envify to make running browserify on React faster, and we added support for five new attributes.
|
||||
|
||||
As always, the release is available for download from the CDN:
|
||||
|
||||
* **React**
|
||||
Dev build with warnings: <http://fb.me/react-0.9.0.js>
|
||||
Minified build for production: <http://fb.me/react-0.9.0.min.js>
|
||||
* **React with Add-Ons**
|
||||
Dev build with warnings: <http://fb.me/react-with-addons-0.9.0.js>
|
||||
Minified build for production: <http://fb.me/react-with-addons-0.9.0.min.js>
|
||||
* **In-Browser JSX Transformer**
|
||||
<http://fb.me/JSXTransformer-0.9.0.js>
|
||||
|
||||
We've also published version `0.9.0` of the `react` and `react-tools` packages on npm and the `react` package on bower.
|
||||
|
||||
## What’s New?
|
||||
|
||||
This version includes better support for normalizing event properties across all supported browsers so that you need to worry even less about cross-browser differences. We've also made many improvements to error messages and have refactored the core to never rethrow errors, so stack traces are more accurate and Chrome's purple break-on-error stop sign now works properly.
|
||||
|
||||
We've also added to the add-ons build [React.addons.TestUtils](/react/docs/test-utils.html), a set of new utilities to help you write unit tests for React components. You can now simulate events on your components, and several helpers are provided to help make assertions about the rendered DOM tree.
|
||||
|
||||
We've also made several other improvements and a few breaking changes; the full changelog is provided below.
|
||||
|
||||
## JSX Whitespace
|
||||
|
||||
In addition to the changes to React core listed below, we've made a small change to the way JSX interprets whitespace to make things more consistent. With this release, space between two components on the same line will be preserved, while a newline separating a text node from a tag will be eliminated in the output. Consider the code:
|
||||
|
||||
```html
|
||||
<div>
|
||||
Monkeys:
|
||||
{listOfMonkeys} {submitButton}
|
||||
</div>
|
||||
```
|
||||
|
||||
In v0.8 and below, it was transformed to the following:
|
||||
|
||||
```javascript
|
||||
React.DOM.div(null,
|
||||
" Monkeys: ",
|
||||
listOfMonkeys, submitButton
|
||||
)
|
||||
```
|
||||
|
||||
In v0.9, it will be transformed to this JS instead:
|
||||
|
||||
```javascript{2,3}
|
||||
React.DOM.div(null,
|
||||
"Monkeys:",
|
||||
listOfMonkeys, " ", submitButton
|
||||
)
|
||||
```
|
||||
|
||||
We believe this new behavior is more helpful and elimates cases where unwanted whitespace was previously added.
|
||||
|
||||
In cases where you want to preserve the space adjacent to a newline, you can write `{'Monkeys: '}` or `Monkeys:{' '}` in your JSX source. We've included a script to do an automated codemod of your JSX source tree that preserves the old whitespace behavior by adding and removing spaces appropriately. You can [install jsx\_whitespace\_transformer from npm](https://github.com/facebook/react/blob/master/npm-jsx_whitespace_transformer/README.md) and run it over your source tree to modify files in place. The transformed JSX files will preserve your code's existing whitespace behavior.
|
||||
|
||||
## Changelog
|
||||
|
||||
### React Core
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
- The lifecycle methods `componentDidMount` and `componentDidUpdate` no longer receive the root node as a parameter; use `this.getDOMNode()` instead
|
||||
- Whenever a prop is equal to `undefined`, the default value returned by `getDefaultProps` will now be used instead
|
||||
- `React.unmountAndReleaseReactRootNode` was previously deprecated and has now been removed
|
||||
- `React.renderComponentToString` is now synchronous and returns the generated HTML string
|
||||
- Full-page rendering (that is, rendering the `<html>` tag using React) is now supported only when starting with server-rendered markup
|
||||
- On mouse wheel events, `deltaY` is no longer negated
|
||||
- When prop types validation fails, a warning is logged instead of an error thrown (with the production build of React, type checks are now skipped for performance)
|
||||
- On `input`, `select`, and `textarea` elements, `.getValue()` is no longer supported; use `.getDOMNode().value` instead
|
||||
- `this.context` on components is now reserved for internal use by React
|
||||
|
||||
#### New Features
|
||||
|
||||
- React now never rethrows errors, so stack traces are more accurate and Chrome's purple break-on-error stop sign now works properly
|
||||
- Added support for SVG tags `defs`, `linearGradient`, `polygon`, `radialGradient`, `stop`
|
||||
- Added support for more attributes:
|
||||
- `crossOrigin` for CORS requests
|
||||
- `download` and `hrefLang` for `<a>` tags
|
||||
- `mediaGroup` and `muted` for `<audio>` and `<video>` tags
|
||||
- `noValidate` and `formNoValidate` for forms
|
||||
- `property` for Open Graph `<meta>` tags
|
||||
- `sandbox`, `seamless`, and `srcDoc` for `<iframe>` tags
|
||||
- `scope` for screen readers
|
||||
- `span` for `<colgroup>` tags
|
||||
- Added support for defining `propTypes` in mixins
|
||||
- Added `any`, `arrayOf`, `component`, `oneOfType`, `renderable`, `shape` to `React.PropTypes`
|
||||
- Added support for `statics` on component spec for static component methods
|
||||
- On all events, `.currentTarget` is now properly set
|
||||
- On keyboard events, `.key` is now polyfilled in all browsers for special (non-printable) keys
|
||||
- On clipboard events, `.clipboardData` is now polyfilled in IE
|
||||
- On drag events, `.dataTransfer` is now present
|
||||
- Added support for `onMouseOver` and `onMouseOut` in addition to the existing `onMouseEnter` and `onMouseLeave` events
|
||||
- Added support for `onLoad` and `onError` on `<img>` elements
|
||||
- Added support for `onReset` on `<form>` elements
|
||||
- The `autoFocus` attribute is now polyfilled consistently on `input`, `select`, and `textarea`
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
- React no longer adds an `__owner__` property to each component's `props` object; passed-in props are now never mutated
|
||||
- When nesting top-level components (e.g., calling `React.renderComponent` within `componentDidMount`), events now properly bubble to the parent component
|
||||
- Fixed a case where nesting top-level components would throw an error when updating
|
||||
- Passing an invalid or misspelled propTypes type now throws an error
|
||||
- On mouse enter/leave events, `.target`, `.relatedTarget`, and `.type` are now set properly
|
||||
- On composition events, `.data` is now properly normalized in IE9 and IE10
|
||||
- CSS property values no longer have `px` appended for the unitless properties `columnCount`, `flex`, `flexGrow`, `flexShrink`, `lineClamp`, `order`, `widows`
|
||||
- Fixed a memory leak when unmounting children with a `componentWillUnmount` handler
|
||||
- Fixed a memory leak when `renderComponentToString` would store event handlers
|
||||
- Fixed an error that could be thrown when removing form elements during a click handler
|
||||
- Boolean attributes such as `disabled` are rendered without a value (previously `disabled="true"`, now simply `disabled`)
|
||||
- `key` values containing `.` are now supported
|
||||
- Shortened `data-reactid` values for performance
|
||||
- Components now always remount when the `key` property changes
|
||||
- Event handlers are attached to `document` only when necessary, improving performance in some cases
|
||||
- Events no longer use `.returnValue` in modern browsers, eliminating a warning in Chrome
|
||||
- `scrollLeft` and `scrollTop` are no longer accessed on document.body, eliminating a warning in Chrome
|
||||
- General performance fixes, memory optimizations, improvements to warnings and error messages
|
||||
|
||||
### React with Addons
|
||||
|
||||
- `React.addons.TestUtils` was added to help write unit tests
|
||||
- `React.addons.TransitionGroup` was renamed to `React.addons.CSSTransitionGroup`
|
||||
- `React.addons.TransitionGroup` was added as a more general animation wrapper
|
||||
- `React.addons.cloneWithProps` was added for cloning components and modifying their props
|
||||
- Bug fix for adding back nodes during an exit transition for CSSTransitionGroup
|
||||
- Bug fix for changing `transitionLeave` in CSSTransitionGroup
|
||||
- Performance optimizations for CSSTransitionGroup
|
||||
- On checkbox `<input>` elements, `checkedLink` is now supported for two-way binding
|
||||
|
||||
### JSX Compiler and react-tools Package
|
||||
|
||||
- Whitespace normalization has changed; now space between two tags on the same line will be preserved, while newlines between two tags will be removed
|
||||
- The `react-tools` npm package no longer includes the React core libraries; use the `react` package instead.
|
||||
- `displayName` is now added in more cases, improving error messages and names in the React Dev Tools
|
||||
- Fixed an issue where an invalid token error was thrown after a JSX closing tag
|
||||
- `JSXTransformer` now uses source maps automatically in modern browsers
|
||||
- `JSXTransformer` error messages now include the filename and problematic line contents when a file fails to parse
|
||||
95
docs/_posts/2014-02-24-community-roundup-17.md
Normal file
95
docs/_posts/2014-02-24-community-roundup-17.md
Normal file
@@ -0,0 +1,95 @@
|
||||
---
|
||||
title: "Community Round-up #17"
|
||||
layout: post
|
||||
author: Jonas Gebhardt
|
||||
---
|
||||
|
||||
|
||||
It's exciting to see the number of real-world React applications and components skyrocket over the past months! This community round-up features a few examples of inspiring React applications and components.
|
||||
|
||||
## React in the Real World
|
||||
|
||||
### Facebook Lookback video editor
|
||||
Large parts of Facebook's web frontend are already powered by React. The recently released Facebook [Lookback video and its corresponding editor](https://www.facebook.com/lookback/edit/) are great examples of a complex, real-world React app.
|
||||
|
||||
### Russia's largest bank is now powered by React
|
||||
Sberbank, Russia's largest bank, recently switched large parts of their site to use React, as detailed in [this post by Vyacheslav Slinko](https://groups.google.com/forum/#!topic/reactjs/Kj6WATX0atg).
|
||||
|
||||
### Relato
|
||||
[Relato](http://bripkens.github.io/relato/) by [Ben Ripkens](https://github.com/bripkens) shows Open Source Statistics based on npm data. It features a filterable and sortable table built in React. Check it out – it's super fast!
|
||||
|
||||
### Makona Editor
|
||||
|
||||
John Lynch ([@johnrlynch](https://twitter.com/johnrlynch)) created Makona, a block-style document editor for the web. Blocks of different content types comprise documents, authored using plain markup. At the switch of a toggle, block contents are then rendered on the page. While not quite a WYSIWYG editor, Makona uses plain textareas for input. This makes it compatible with a wider range of platforms than traditional rich text editors.
|
||||
<figure>[](http://johnthethird.github.io/makona-editor/)</figure>
|
||||
|
||||
### Create Chrome extensions using React
|
||||
React is in no way limited to just web pages. Brandon Tilley ([@BinaryMuse](https://twitter.com/BinaryMuse)) just released a detailed walk-through of [how he built his Chrome extension "Fast Tab Switcher" using React](http://brandontilley.com/2014/02/24/creating-chrome-extensions-with-react.html).
|
||||
|
||||
|
||||
### Twitter Streaming Client
|
||||
|
||||
Javier Aguirre ([@javaguirre](https://twitter.com/javaguirre)) put together a simple [twitter streaming client using node, socket.io and React](http://javaguirre.net/2014/02/11/twitter-streaming-api-with-node-socket-io-and-reactjs/).
|
||||
|
||||
|
||||
### Sproutsheet
|
||||
|
||||
[Sproutsheet](http://sproutsheet.com/) is a gardening calendar. You can use it to track certain events that happen in the life of your plants. It's currently in beta and supports localStorage, and data/image import and export.
|
||||
|
||||
### Instant Domain Search
|
||||
[Instant Domain Search](https://instantdomainsearch.com/) also uses React. It sure is instant!
|
||||
|
||||
|
||||
### SVG-based graphical node editor
|
||||
[NoFlo](http://noflojs.org/) and [Meemoo](http://meemoo.org/) developer [Forresto Oliphant](http://www.forresto.com/) built an awesome SVG-based [node editor](http://forresto.github.io/prototyping/react/) in React.
|
||||
<figure>[](http://forresto.github.io/prototyping/react/)</figure>
|
||||
|
||||
|
||||
### Ultimate Tic-Tac-Toe Game in React
|
||||
Rafał Cieślak ([@Ravicious](https://twitter.com/Ravicious)) wrote a [React version](http://ravicious.github.io/ultimate-ttt/) of [Ultimate Tic Tac Toe](http://mathwithbaddrawings.com/2013/06/16/ultimate-tic-tac-toe/). Find the source [here](https://github.com/ravicious/ultimate-ttt).
|
||||
|
||||
|
||||
|
||||
### ReactJS Gallery
|
||||
|
||||
[Emanuele Rampichini](https://github.com/lele85)'s [ReactJS Gallery](https://github.com/lele85/ReactGallery) is a cool demo app that shows fullscreen images from a folder on the server. If the folder content changes, the gallery app updates via websockets.
|
||||
|
||||
Emanuele shared this awesome demo video with us:
|
||||
|
||||
<iframe width="560" height="315" src="//www.youtube.com/embed/jYcpaemt90M" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
|
||||
|
||||
## React Components
|
||||
|
||||
|
||||
### Table Sorter
|
||||
[Table Sorter](http://bgerm.github.io/react-table-sorter-demo/) by [bgerm](https://github.com/bgerm) [[source](https://github.com/bgerm/react-table-sorter-demo)] is another helpful React component.
|
||||
|
||||
### Static-search
|
||||
|
||||
Dmitry Chestnykh [@dchest](https://twitter.com/dchest) wrote a [static search indexer](https://github.com/dchest/static-search) in Go, along with a [React-based web front-end](http://www.codingrobots.com/search/) that consumes search result via JSON.
|
||||
|
||||
### Lorem Ipsum component
|
||||
|
||||
[Martin Andert](https://github.com/martinandert) created [react-lorem-component](https://github.com/martinandert/react-lorem-component), a simple component for all your placeholding needs.
|
||||
|
||||
### Input with placeholder shim
|
||||
[react-input=placeholder](https://github.com/enigma-io/react-input-placeholder) by [enigma-io](https://github.com/enigma-io) is a small wrapper around React.DOM.input that shims in placeholder functionality for browsers that don't natively support it.
|
||||
|
||||
### diContainer
|
||||
|
||||
[dicontainer](https://github.com/SpektrumFM/dicontainer) provides a dependency container that lets you inject Angular-style providers and services as simple React.js Mixins.
|
||||
|
||||
|
||||
## React server rendering
|
||||
|
||||
Ever wonder how to pre-render React components on the server? [react-server-example](https://github.com/mhart/react-server-example) by Michael Hart ([@hichaelmart](http://twitter.com/hichaelmart)) walks through the necessary steps.
|
||||
|
||||
Similarly, Alan deLevie ([@adelevie](https://twitter.com/adelevie)) created [react-client-server-starter](https://github.com/adelevie/react-client-server-starter), another detailed walk-through of how to server-render your app.
|
||||
|
||||
|
||||
|
||||
## Random Tweet
|
||||
|
||||
<div><blockquote class="twitter-tweet" lang="en"><p>Recent changes: web ui is being upgraded to [#reactjs](https://twitter.com/search?q=%23reactjs&src=hash), HEAD~4 at [https://camlistore.googlesource.com/camlistore/](https://camlistore.googlesource.com/camlistore/)</p>— Camlistore (@Camlistore) <a href="https://twitter.com/Camlistore/status/423925795820539904">January 16, 2014</a></blockquote></div>
|
||||
106
docs/_posts/2014-03-14-community-roundup-18.md
Normal file
106
docs/_posts/2014-03-14-community-roundup-18.md
Normal file
@@ -0,0 +1,106 @@
|
||||
---
|
||||
title: "Community Round-up #18"
|
||||
layout: post
|
||||
author: Jonas Gebhardt
|
||||
---
|
||||
|
||||
In this Round-up, we are taking a few closer looks at React's interplay with different frameworks and architectures.
|
||||
|
||||
## "Little framework BIG splash"
|
||||
|
||||
Let's start with yet another refreshing introduction to React: Craig Savolainen ([@maedhr](https://twitter.com/maedhr)) walks through some first steps, demonstrating [how to build a Google Maps component](http://infinitemonkeys.influitive.com/little-framework-big-splash) using React.
|
||||
|
||||
## Architecting your app with react
|
||||
|
||||
Brandon Konkle ([@bkonkle](https://twitter.com/bkonkle))
|
||||
[Architecting your app with react](http://lincolnloop.com/blog/architecting-your-app-react-part-1/)
|
||||
We're looking forward to part 2!
|
||||
|
||||
> React is not a full MVC framework, and this is actually one of its strengths. Many who adopt React choose to do so alongside their favorite MVC framework, like Backbone. React has no opinions about routing or syncing data, so you can easily use your favorite tools to handle those aspects of your frontend application. You'll often see React used to manage specific parts of an application's UI and not others. React really shines, however, when you fully embrace its strategies and make it the core of your application's interface.
|
||||
>
|
||||
> [Read the full article...](http://lincolnloop.com/blog/architecting-your-app-react-part-1/)
|
||||
|
||||
## React vs. async DOM manipulation
|
||||
|
||||
Eliseu Monar ([@eliseumds](https://twitter.com/eliseumds))'s post "[ReactJS vs async concurrent rendering](http://eliseumds.tumblr.com/post/77843550010/vitalbox-pchr-reactjs-vs-async-concurrent-rendering)" is a great example of how React quite literally renders a whole array of common web development work(arounds) obsolete.
|
||||
|
||||
|
||||
|
||||
## React, Scala and the Play Framework
|
||||
[Matthias Nehlsen](http://matthiasnehlsen.com/) wrote a detailed introductory piece on [React and the Play Framework](http://matthiasnehlsen.com/blog/2014/01/05/play-framework-and-facebooks-react-library/), including a helpful architectural diagram of a typical React app.
|
||||
|
||||
Nehlsen's React frontend is the second implementation of his chat application's frontend, following an AngularJS version. Both implementations are functionally equivalent and offer some perspective on differences between the two frameworks.
|
||||
|
||||
In [another article](http://matthiasnehlsen.com/blog/2014/01/24/scala-dot-js-and-reactjs/), he walks us through the process of using React with scala.js to implement app-wide undo functionality.
|
||||
|
||||
Also check out his [talk](http://m.ustream.tv/recorded/42780242) at Ping Conference 2014, in which he walks through a lot of the previously content in great detail.
|
||||
|
||||
## React and Backbone
|
||||
|
||||
The folks over at [Venmo](https://venmo.com/) are using React in conjunction with Backbone.
|
||||
Thomas Boyt ([@thomasaboyt](https://twitter.com/thomasaboyt)) wrote [this detailed piece](http://www.thomasboyt.com/2013/12/17/using-reactjs-as-a-backbone-view.html) about why React and Backbone are "a fantastic pairing".
|
||||
|
||||
## React vs. Ember
|
||||
|
||||
Eric Berry ([@coderberry](https://twitter.com/coderberry)) developed Ember equivalents for some of the official React examples. Read his post for a side-by-side comparison of the respective implementations: ["Facebook React vs. Ember"](http://instructure.github.io/blog/2013/12/17/facebook-react-vs-ember/).
|
||||
|
||||
|
||||
## React and plain old HTML
|
||||
|
||||
Daniel Lo Nigro ([@Daniel15](https://twitter.com/Daniel15)) created [React-Magic](https://github.com/reactjs/react-magic), which leverages React to ajaxify plain old html pages and even [allows CSS transitions between pageloads](http://stuff.dan.cx/facebook/react-hacks/magic/red.php).
|
||||
|
||||
> React-Magic intercepts all navigation (link clicks and form posts) and loads the requested page via an AJAX request. React is then used to "diff" the old HTML with the new HTML, and only update the parts of the DOM that have been changed.
|
||||
>
|
||||
> [Check out the project on GitHub...](https://github.com/reactjs/react-magic)
|
||||
|
||||
On a related note, [Reactize](https://turbo-react.herokuapp.com/) by Ross Allen ([@ssorallen](https://twitter.com/ssorallen)) is a similarly awesome project: A wrapper for Rails' [Turbolinks](https://github.com/rails/turbolinks/), which seems to have inspired John Lynch ([@johnrlynch](https://twitter.com/johnrlynch)) to then create [a server-rendered version using the JSX transformer in Rails middleware](http://www.rigelgroupllc.com/blog/2014/01/12/react-jsx-transformer-in-rails-middleware/).
|
||||
|
||||
## React and Object.observe
|
||||
Check out [François de Campredon](https://github.com/fdecampredon)'s implementation of [TodoMVC based on React and ES6's Object.observe](https://github.com/fdecampredon/react-observe-todomvc/).
|
||||
|
||||
|
||||
## React and Angular
|
||||
|
||||
Ian Bicking ([@ianbicking](https://twitter.com/ianbicking)) of Mozilla Labs [explains why he "decided to go with React instead of Angular.js"](https://plus.google.com/+IanBicking/posts/Qj8R5SWAsfE).
|
||||
|
||||
### ng-React Update
|
||||
|
||||
[David Chang](https://github.com/davidchang) works through some performance improvements of his [ngReact](https://github.com/davidchang/ngReact) project. His post ["ng-React Update - React 0.9 and Angular Track By"](http://davidandsuzi.com/ngreact-update/) includes some helpful advice on boosting render performance for Angular components.
|
||||
|
||||
> Angular gives you a ton of functionality out of the box - a full MV* framework - and I am a big fan, but I'll admit that you need to know how to twist the right knobs to get performance.
|
||||
>
|
||||
> That said, React gives you a very strong view component out of the box with the performance baked right in. Try as I did, I couldn't actually get it any faster. So pretty impressive stuff.
|
||||
>
|
||||
>[Read the full post...](http://davidandsuzi.com/ngreact-update/)
|
||||
|
||||
|
||||
React was also recently mentioned at ng-conf, where the Angular team commented on React's concept of the virtual DOM:
|
||||
|
||||
<iframe width="560" height="315" src="//www.youtube.com/embed/srt3OBP2kGc?start=113" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
## React and Web Components
|
||||
|
||||
Jonathan Krause ([@jonykrause](https://twitter.com/jonykrause)) offers his thoughts regarding [parallels between React and Web Components](http://jonykrau.se/posts/the-value-of-react), highlighting the value of React's ability to render pages on the server practically for free.
|
||||
|
||||
## Immutable React
|
||||
|
||||
[Peter Hausel](http://pk11.kinja.com/) shows how to build a Wikipedia auto-complete demo based on immutable data structures (similar to [mori](https://npmjs.org/package/mori)), really taking advantage of the framework's one-way reactive data binding:
|
||||
|
||||
> Its truly reactive design makes DOM updates finally sane and when combined with persistent data structures one can experience JavaScript development like it was never done before.
|
||||
|
||||
> [Read the full post](http://tech.kinja.com/immutable-react-1495205675)
|
||||
|
||||
|
||||
## D3 and React
|
||||
|
||||
[Ben Smith](http://10consulting.com/) built some great SVG-based charting components using a little less of D3 and a little more of React: [D3 and React - the future of charting components?](http://10consulting.com/2014/02/19/d3-plus-reactjs-for-charting/)
|
||||
|
||||
## Om and React
|
||||
Josh Haberman ([@joshhaberman](https://twitter.com/JoshHaberman)) discusses performance differences between React, Om and traditional MVC frameworks in "[A closer look at OM vs React performance](http://blog.reverberate.org/2014/02/on-future-of-javascript-mvc-frameworks.html)".
|
||||
|
||||
Speaking of Om: [Omchaya](https://github.com/sgrove/omchaya) by Sean Grove ([@sgrove](https://twitter.com/sgrove)) is a neat Cljs/Om example project.
|
||||
|
||||
|
||||
## Random Tweets
|
||||
|
||||
<div><blockquote class="twitter-tweet" lang="en"><p>Worked for 2 hours on a [@react_js](https://twitter.com/react_js) app sans internet. Love that I could get stuff done with it without googling every question.</p>— John Shimek (@varikin) <a href="https://twitter.com/varikin/status/436606891657949185">February 20, 2014</a></blockquote></div>
|
||||
72
docs/_posts/2014-03-19-react-v0.10-rc1.md
Normal file
72
docs/_posts/2014-03-19-react-v0.10-rc1.md
Normal file
@@ -0,0 +1,72 @@
|
||||
---
|
||||
title: React v0.10 RC
|
||||
layout: post
|
||||
author: Paul O’Shannessy
|
||||
---
|
||||
|
||||
[v0.9 has only been out for a month](http://facebook.github.io/react/blog/2014/02/20/react-v0.9.html), but we’re getting ready to push out v0.10 already. Unlike v0.9 which took a long time, we don't have a long list of changes to talk about.
|
||||
|
||||
The release candidate is available for download from the CDN:
|
||||
|
||||
* **React**
|
||||
Dev build with warnings: <http://fb.me/react-0.10.0-rc1.js>
|
||||
Minified build for production: <http://fb.me/react-0.10.0-rc1.min.js>
|
||||
* **React with Add-Ons**
|
||||
Dev build with warnings: <http://fb.me/react-with-addons-0.10.0-rc1.js>
|
||||
Minified build for production: <http://fb.me/react-with-addons-0.10.0-rc1.min.js>
|
||||
* **In-Browser JSX transformer**
|
||||
<http://fb.me/JSXTransformer-0.10.0-rc1.js>
|
||||
|
||||
We've also published version `0.10.0-rc1` of the `react` and `react-tools` packages on npm and the `react` package on bower.
|
||||
|
||||
Please try these builds out and [file an issue on GitHub](https://github.com/facebook/react/issues/new) if you see anything awry.
|
||||
|
||||
## Clone On Mount
|
||||
|
||||
The main purpose of this release is to provide a smooth upgrade path as we evolve some of the implementation of core. In v0.9 we started warning in cases where you called methods on unmounted components. This is part of an effort to enforce the idea that the return value of a component (`React.DOM.div()`, `MyComponent()`) is in fact not a reference to the component instance React uses in the virtual DOM. The return value is instead a light-weight object that React knows how to use. Since the return value currently is a reference to the same object React uses internally, we need to make this transition in stages as many people have come to depend on this implementation detail.
|
||||
|
||||
In 0.10, we’re adding more warnings to catch a similar set of patterns. When a component is mounted we clone it and use that object for our internal representation. This allows us to capture calls you think you’re making to a mounted component. We’ll forward them on to the right object, but also warn you that this is breaking. See “Access to the Mounted Instance” on [this page](http://fb.me/react-warning-descriptors). Most of the time you can solve your pattern by using refs.
|
||||
|
||||
Storing a reference to your top level component is a pattern touched upon on that page, but another examples that demonstrates what we see a lot of:
|
||||
|
||||
```js
|
||||
// This is a common pattern. However instance here really refers to a
|
||||
// "descriptor", not necessarily the mounted instance.
|
||||
var instance = <MyComponent/>;
|
||||
React.renderComponent(instance);
|
||||
// ...
|
||||
instance.setProps(...);
|
||||
|
||||
// The change here is very simple. The return value of renderComponent will be
|
||||
// the mounted instance.
|
||||
var instance = React.renderComponent(<MyComponent/>)
|
||||
// ...
|
||||
instance.setProps(...);
|
||||
```
|
||||
|
||||
These warnings and method forwarding are only enabled in the development build. The production builds continue to work as they did in v0.9. We strongly encourage you to use the development builds to catch these warnings and fix the call sites.
|
||||
|
||||
The plan for v0.11 is that we will go fully to "descriptors". Method calls on the return value of `MyComponent()` will fail hard.
|
||||
|
||||
## Changelog
|
||||
|
||||
### React Core
|
||||
|
||||
#### New Features
|
||||
* Added warnings to help migrate towards descriptors
|
||||
* Made it possible to server render without React-related markup (`data-reactid`, `data-react-checksum`). This DOM will not be mountable by React. [Read the docs for `React.renderComponentToStaticMarkup`](/react/docs/top-level-api.html#react.rendercomponenttostaticmarkup)
|
||||
* Added support for more attributes:
|
||||
* `srcSet` for `<img>` to specify images at different pixel ratios
|
||||
* `textAnchor` for SVG
|
||||
|
||||
#### Bug Fixes
|
||||
* Ensure all void elements don’t insert a closing tag into the markup.
|
||||
* Ensure `className={false}` behaves consistently
|
||||
* Ensure `this.refs` is defined, even if no refs are specified.
|
||||
|
||||
### Addons
|
||||
|
||||
* `update` function to deal with immutable data. [Read the docs](/react/docs/update.html)
|
||||
|
||||
### react-tools
|
||||
* Added an option argument to `transform` function. The only option supported is `harmony`, which behaves the same as `jsx --harmony` on the command line. This uses the ES6 transforms from [jstransform](https://github.com/facebook/jstransform).
|
||||
73
docs/_posts/2014-03-21-react-v0.10.md
Normal file
73
docs/_posts/2014-03-21-react-v0.10.md
Normal file
@@ -0,0 +1,73 @@
|
||||
---
|
||||
title: React v0.10
|
||||
layout: post
|
||||
author: Paul O’Shannessy
|
||||
---
|
||||
|
||||
Hot on the heels of the [release candidate earlier this week](/react/blog/2014/03/19/react-v0.10-rc1.html), we're ready to call v0.10 done. The only major issue we discovered had to do with the `react-tools` package, which has been updated. We've copied over the changelog from the RC with some small clarifying changes.
|
||||
|
||||
The release is available for download from the CDN:
|
||||
|
||||
* **React**
|
||||
Dev build with warnings: <http://fb.me/react-0.10.0.js>
|
||||
Minified build for production: <http://fb.me/react-0.10.0.min.js>
|
||||
* **React with Add-Ons**
|
||||
Dev build with warnings: <http://fb.me/react-with-addons-0.10.0.js>
|
||||
Minified build for production: <http://fb.me/react-with-addons-0.10.0.min.js>
|
||||
* **In-Browser JSX transformer**
|
||||
<http://fb.me/JSXTransformer-0.10.0.js>
|
||||
|
||||
We've also published version `0.10.0` of the `react` and `react-tools` packages on npm and the `react` package on bower.
|
||||
|
||||
Please try these builds out and [file an issue on GitHub](https://github.com/facebook/react/issues/new) if you see anything awry.
|
||||
|
||||
## Clone On Mount
|
||||
|
||||
The main purpose of this release is to provide a smooth upgrade path as we evolve some of the implementation of core. In v0.9 we started warning in cases where you called methods on unmounted components. This is part of an effort to enforce the idea that the return value of a component (`React.DOM.div()`, `MyComponent()`) is in fact not a reference to the component instance React uses in the virtual DOM. The return value is instead a light-weight object that React knows how to use. Since the return value currently is a reference to the same object React uses internally, we need to make this transition in stages as many people have come to depend on this implementation detail.
|
||||
|
||||
In 0.10, we’re adding more warnings to catch a similar set of patterns. When a component is mounted we clone it and use that object for our internal representation. This allows us to capture calls you think you’re making to a mounted component. We’ll forward them on to the right object, but also warn you that this is breaking. See “Access to the Mounted Instance” on [this page](http://fb.me/react-warning-descriptors). Most of the time you can solve your pattern by using refs.
|
||||
|
||||
Storing a reference to your top level component is a pattern touched upon on that page, but another examples that demonstrates what we see a lot of:
|
||||
|
||||
```js
|
||||
// This is a common pattern. However instance here really refers to a
|
||||
// "descriptor", not necessarily the mounted instance.
|
||||
var instance = <MyComponent/>;
|
||||
React.renderComponent(instance);
|
||||
// ...
|
||||
instance.setProps(...);
|
||||
|
||||
// The change here is very simple. The return value of renderComponent will be
|
||||
// the mounted instance.
|
||||
var instance = React.renderComponent(<MyComponent/>)
|
||||
// ...
|
||||
instance.setProps(...);
|
||||
```
|
||||
|
||||
These warnings and method forwarding are only enabled in the development build. The production builds continue to work as they did in v0.9. We strongly encourage you to use the development builds to catch these warnings and fix the call sites.
|
||||
|
||||
The plan for v0.11 is that we will go fully to "descriptors". Method calls on the return value of `MyComponent()` will fail hard.
|
||||
|
||||
## Changelog
|
||||
|
||||
### React Core
|
||||
|
||||
#### New Features
|
||||
* Added warnings to help migrate towards descriptors
|
||||
* Made it possible to server render without React-related markup (`data-reactid`, `data-react-checksum`). This DOM will not be mountable by React. [Read the docs for `React.renderComponentToStaticMarkup`](/react/docs/top-level-api.html#react.rendercomponenttostaticmarkup)
|
||||
* Added support for more attributes:
|
||||
* `srcSet` for `<img>` to specify images at different pixel ratios
|
||||
* `textAnchor` for SVG
|
||||
|
||||
#### Bug Fixes
|
||||
* Ensure all void elements don’t insert a closing tag into the markup.
|
||||
* Ensure `className={false}` behaves consistently
|
||||
* Ensure `this.refs` is defined, even if no refs are specified.
|
||||
|
||||
### Addons
|
||||
|
||||
* `update` function to deal with immutable data. [Read the docs](/react/docs/update.html)
|
||||
|
||||
### react-tools
|
||||
* Added an option argument to `transform` function. The only option supported is `harmony`, which behaves the same as `jsx --harmony` on the command line. This uses the ES6 transforms from [jstransform](https://github.com/facebook/jstransform).
|
||||
|
||||
57
docs/_posts/2014-03-28-the-road-to-1.0.md
Normal file
57
docs/_posts/2014-03-28-the-road-to-1.0.md
Normal file
@@ -0,0 +1,57 @@
|
||||
---
|
||||
title: The Road to 1.0
|
||||
layout: post
|
||||
author: Paul O'Shannessy
|
||||
---
|
||||
|
||||
When we launched React last spring, we purposefully decided not to call it 1.0. It was production ready, but we had plans to evolve APIs and behavior as we saw how people were using React, both internally and externally. We've learned a lot over the past 9 months and we've thought a lot about what 1.0 will mean for React. A couple weeks ago, I outlined [several projects][projects] that we have planned to take us to 1.0 and beyond. Today I'm writing a bit more about them to give our users a better insight into our plans.
|
||||
|
||||
Our primary goal with 1.0 is to clarify our messaging and converge on an API that is aligned with our goals. In order to do that, we want to clean up bad patterns we've seen in use and really help enable developers write good code.
|
||||
|
||||
## Descriptors
|
||||
|
||||
The first part of this is what we're calling "descriptors". I talked about this briefly in our [v0.10 announcements][v0.10]. The goal here is to separate our virtual DOM representation from our use of it. Simply, this means the return value of a component (e.g. `React.DOM.div()`, `MyComponent()`) will be a simple object containing the information React needs to render. Currently the object returned is actually linked to React's internal representation of the component and even directly to the DOM element. This has enabled some bad patterns that are quite contrary to how we want people to use React. That's our failure.
|
||||
|
||||
We added some warnings in v0.9 to start migrating some of these bad patterns. With v0.10 we'll catch more. You'll see more on this soon as we expect to ship v0.11 with descriptors.
|
||||
|
||||
## API Cleanup
|
||||
|
||||
This is really connected to everything. We want to keep the API as simple as possible and help developers [fall into the pit of success][pitofsuccess]. Enabling bad patterns with bad APIs is not success.
|
||||
|
||||
## ES6
|
||||
|
||||
Before we even launched React publicly, members of the team were talking about how we could leverage ES6, namely classes, to improve the experience of creating React components. Calling `React.createClass(...)` isn't great. We don't quite have the right answer here yet, but we're close. We want to make sure we make this as simple as possible. It could look like this:
|
||||
|
||||
```js
|
||||
class MyComponent extends React.Component {
|
||||
render() {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
There are other features of ES6 we're already using in core. I'm sure we'll see more of that. The `jsx` executable we ship with `react-tools` already supports transforming many parts of ES6 into code that will run on older browsers.
|
||||
|
||||
## Context
|
||||
|
||||
While we haven't documented `context`, it exists in some form in React already. It exists as a way to pass values through a tree without having to use props at every single point. We've seen this need crop up time and time again, so we want to make this as easy as possible. It's use has performance tradeoffs, and there are known weaknesses in our implementation, so we want to make sure this is a solid feature.
|
||||
|
||||
## Addons
|
||||
|
||||
As you may know, we ship a separate build of React with some extra features we called "addons". While this has served us fine, it's not great for our users. It's made testing harder, but also results in more cache misses for people using a CDN. The problem we face is that many of these "addons" need access to parts of React that we don't expose publicly. Our goal is to ship each addon on its own and let each hook into React as needed. This would also allow others to write and distribute "addons".
|
||||
|
||||
## Browser Support
|
||||
|
||||
As much as we'd all like to stop supporting older browsers, it's not always possible. Facebook still supports IE8. While React won't support IE8 forever, our goal is to have 1.0 support IE8. Hopefully we can continue to abstract some of these rough parts.
|
||||
|
||||
## Animations
|
||||
|
||||
Finding a way to define animations in a declarative way is a hard problem. We've been exploring the space for a long time. We've introduced some half-measures to alleviate some use cases, but the larger problem remains. While we'd like to make this a part of 1.0, realistically we don't think we'll have a good solution in place.
|
||||
|
||||
## Miscellaneous
|
||||
|
||||
There are several other things I listed on [our projects page][projects] that we're tracking. Some of them are internals and have no obvious outward effect (improve tests, repo separation, updated test runner). I encourage you to take a look.
|
||||
|
||||
[v0.10]: http://facebook.github.io/react/blog/2014/03/21/react-v0.10.html
|
||||
[pitofsuccess]: http://blog.codinghorror.com/falling-into-the-pit-of-success/
|
||||
[projects]: https://github.com/facebook/react/wiki/Projects
|
||||
38
docs/_posts/2014-04-04-reactnet.md
Normal file
38
docs/_posts/2014-04-04-reactnet.md
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
title: "Use React and JSX in ASP.NET MVC"
|
||||
layout: post
|
||||
author: Daniel Lo Nigro
|
||||
---
|
||||
|
||||
Today we're happy to announce the initial release of
|
||||
[ReactJS.NET](http://reactjs.net/), which makes it easier to use React and JSX
|
||||
in .NET applications, focusing specifically on ASP.NET MVC web applications.
|
||||
It has several purposes:
|
||||
|
||||
- On-the-fly JSX to JavaScript compilation. Simply reference JSX files and they
|
||||
will be compiled and cached server-side.
|
||||
|
||||
```html
|
||||
<script src="@Url.Content("/Scripts/HelloWorld.jsx")"></script>
|
||||
```
|
||||
- JSX to JavaScript compilation via popular minification/combination libraries
|
||||
(Cassette and ASP.NET Bundling and Minification). This is suggested for
|
||||
production websites.
|
||||
- Server-side component rendering to make your initial render super fast.
|
||||
|
||||
Even though we are focusing on ASP.NET MVC, ReactJS.NET can also be used in
|
||||
Web Forms applications as well as non-web applications (for example, in build
|
||||
scripts). ReactJS.NET currently only works on Microsoft .NET but we are working
|
||||
on support for Linux and Mac OS X via Mono as well.
|
||||
|
||||
Installation
|
||||
------------
|
||||
ReactJS.NET is packaged in NuGet. Simply run `Install-Package React.Mvc4` in the
|
||||
package manager console or search NuGet for "React" to install it.
|
||||
[See the documentation](http://reactjs.net/docs) for more information. The
|
||||
GitHub project contains
|
||||
[a sample website](https://github.com/reactjs/React.NET/tree/master/src/React.Sample.Mvc4)
|
||||
demonstrating all of the features.
|
||||
|
||||
Let us know what you think, and feel free to send through any feedback and
|
||||
report bugs [on GitHub](https://github.com/reactjs/React.NET).
|
||||
17
docs/_posts/2014-05-06-flux.md
Normal file
17
docs/_posts/2014-05-06-flux.md
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
title: "Flux: An Application Architecture for React"
|
||||
layout: post
|
||||
author: Bill Fisher and Jing Chen
|
||||
---
|
||||
|
||||
We recently spoke at one of f8's breakout session about Flux, a data flow architecture that works well with React. Check out the video here:
|
||||
|
||||
<figure><iframe width="560" height="315" src="//www.youtube.com/embed/nYkdrAPrdcw?list=PLb0IAmt7-GS188xDYE-u1ShQmFFGbrk0v" frameborder="0" allowfullscreen></iframe></figure>
|
||||
|
||||
To summarize, Flux works well for us because the single directional data flow makes it easy to understand and modify an application as it becomes more complicated. We found that two-way data bindings lead to cascading updates, where changing one data model led to another data model updating, making it very difficult to predict what would change as the result of a single user interaction.
|
||||
|
||||
In Flux, the Dispatcher is a singleton that directs the flow of data and ensures that updates do not cascade. As an application grows, the Dispatcher becomes more vital, as it can also manage dependencies between stores by invoking the registered callbacks in a specific order.
|
||||
|
||||
When a user interacts with a React view, the view sends an action (usually represented as a JavaScript object with some fields) through the dispatcher, which notifies the various stores that hold the application's data and business logic. When the stores change state, they notify the views that something has updated. This works especially well with React's declarative model, which allows the stores to send updates without specifying how to transition views between states.
|
||||
|
||||
Flux is more of a pattern than a formal framework, so you can start using Flux immediately without a lot of new code. An [example of this architecture](https://github.com/facebook/react/tree/master/examples/todomvc-flux) is available, along with more [detailed documentation](http://facebook.github.io/react/docs/flux-overview.html) and a [tutorial](http://facebook.github.io/react/docs/flux-todo-list.html). Look for more examples to come in the future.
|
||||
15
docs/_posts/2014-05-29-one-year-of-open-source-react.md
Normal file
15
docs/_posts/2014-05-29-one-year-of-open-source-react.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
title: "One Year of Open-Source React"
|
||||
layout: post
|
||||
author: Cheng Lou
|
||||
---
|
||||
|
||||
Today marks the one-year open-source anniversary of React.
|
||||
|
||||
It’s been a crazy ride. 2.3k commits and 1.5k issues and pull requests later, we’re approaching version 1.0 and nearing 7k Github stars, with big names such as Khan Academy, New York Times, and Airbnb (and naturally, Facebook and Instagram) using React in production, and many more developers blogging their success stories with it. The [roadmap](http://facebook.github.io/react/blog/2014/03/28/the-road-to-1.0.html) gives a glimpse into the future of the library; exciting stuff lies ahead!
|
||||
|
||||
Every success has its story. React was born out of our frustration at existing solutions for building UIs. When it was first suggested at Facebook, few people thought that functionally re-rendering everything and diffing the results could ever perform well. However, support grew after we built the first implementation and people wrote their first components. When we open-sourced React, the initial reception was [similarly skeptical](http://www.reddit.com/r/programming/comments/1fak87/react_facebooks_latest_javascript_client_library/). It challenges many pre-established conventions and received mostly disapproving first-impressions, intermingled with positive ones that often were votes of confidence in Facebook’s engineering capabilities. On an open, competitive platform such as the web, it's been hard to convince people to try React. [JSX](http://facebook.github.io/react/docs/jsx-in-depth.html), in particular, filtered out a huge chunk of potential early adopters.
|
||||
|
||||
Fast forward one year, React has strongly [grown in popularity](https://news.ycombinator.com/item?id=7489959). Special acknowledgments go to Khan Academy, the ClojureScript community, and established frameworks such as Ember and Angular for contributing to and debating on our work. We'd also like to thank all the [individual contributors](https://github.com/facebook/react/graphs/contributors) who have taken the time to help out over the past year. React, as a library and as a new paradigm on the web, wouldn't have gained as much traction without them. In the future, we will continue to try to set an example of what's possible to achieve when we rethink about current “best practices”.
|
||||
|
||||
Here’s to another year!
|
||||
55
docs/_posts/2014-06-27-community-roundup-19.md
Normal file
55
docs/_posts/2014-06-27-community-roundup-19.md
Normal file
@@ -0,0 +1,55 @@
|
||||
---
|
||||
title: "Community Round-up #19"
|
||||
layout: post
|
||||
author: Cheng Lou
|
||||
---
|
||||
|
||||
## React Meetups!
|
||||
Ever wanted to find developers who also share the same interest in React than you? Recently, there has been a React Meetup in [San Francisco](http://www.meetup.com/ReactJS-San-Francisco/) (courtesy of [Telmate](http://www.telmate.com)), and one in [London](http://www.meetup.com/London-React-User-Group/) (courtesy of [Stuart Harris](http://www.meetup.com/London-React-User-Group/members/105837542/), [Cain Ullah](http://www.meetup.com/London-React-User-Group/members/15509971/) and [Zoe Merchant](http://www.meetup.com/London-React-User-Group/members/137058242/)). These two events have been big successes; a second one in London is [already planned](http://www.meetup.com/London-React-User-Group/events/191406572/).
|
||||
|
||||
If you don't live near San Francisco or London, why not start one in your community?
|
||||
|
||||
## Complementary Tools
|
||||
In case you haven't seen it, we've consolidated the tooling solution around React on [this wiki page](https://github.com/facebook/react/wiki/Complementary-Tools). Some of the notable recent entries include:
|
||||
|
||||
- [Ryan Florence](https://github.com/rpflorence) and [Michael Jackson](https://github.com/mjackson)'s [react-nested-router](https://github.com/rpflorence/react-nested-router), which is a translation of the Ember router API to React.
|
||||
|
||||
- [Stephen J. Collings](https://github.com/stevoland)'s [react-bootstrap](https://github.com/react-bootstrap/react-bootstrap), which wraps the popular framework with a bit of React goodness. The [website](http://react-bootstrap.github.io/components.html) features live-editable demos.
|
||||
|
||||
- [Andrey Popp](https://github.com/andreypopp)'s [react-quickstart](https://github.com/andreypopp/react-quickstart), which gives you a quick template for server-side rendering and routing, among other features.
|
||||
|
||||
These are some of the links that often pop up on the #reactjs IRC channel. If you made something that you think deserves to be shown on the wiki, feel free to add it!
|
||||
|
||||
## React in Interesting Places
|
||||
|
||||
The core concepts React themselves is something very valuable that the community is exploring and pushing further. A year ago, we wouldn't have imagined something like [Bruce Hauman](http://rigsomelight.com)'s [Flappy Bird ClojureScript port](http://rigsomelight.com/2014/05/01/interactive-programming-flappy-bird-clojurescript.html), whose interactive programming has been made possible through React:
|
||||
|
||||
<iframe width="560" height="315" src="//www.youtube.com/embed/KZjFVdU8VLI" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
And don't forget [Pete Hunt](https://github.com/petehunt)'s Wolfenstein 3D rendering engine in React ([source code](https://github.com/petehunt/wolfenstein3D-react/blob/master/js/renderer.js#L183)). While it's nearly a year old, it's still a nice demo.
|
||||
|
||||
[](http://www.petehunt.net/wolfenstein3D-react/wolf3d.html)
|
||||
|
||||
Give us a shoutout on IRC or [React Google Groups](https://groups.google.com/forum/#!forum/reactjs) if you've used React in some Interesting places.
|
||||
|
||||
## Even More People Using React
|
||||
|
||||
### Prismatic
|
||||
[Prismatic](http://getprismatic.com/home) recently shrank their codebase fivefold with the help of React and its popular ClojureScript wrapper, [Om](https://github.com/swannodette/om). They detailed their very positive experience [here](http://blog.getprismatic.com/om-sweet-om-high-functional-frontend-engineering-with-clojurescript-and-react/).
|
||||
|
||||
> Finally, the state is normalized: each piece of information is represented in a single place. Since React ensures consistency between the DOM and the application data, the programmer can focus on ensuring that the state properly stays up to date in response to user input. If the application state is normalized, then this consistency is guaranteed by definition, completely avoiding the possibility of an entire class of common bugs.
|
||||
|
||||
### Adobe Brackets
|
||||
[Kevin Dangoor](http://www.kevindangoor.com) works on [Brackets](http://brackets.io/?lang=en), the open-source code editor. After writing [his first impression on React](http://www.kevindangoor.com/2014/05/simplifying-code-with-react/), he followed up with another insightful [article](http://www.kevindangoor.com/2014/05/react-in-brackets/) on how to gradually make the code transition, how to preserve the editor's good parts, and how to tune Brackets' tooling around JSX.
|
||||
|
||||
> We don’t need to switch to React everywhere, all at once. It’s not a framework that imposes anything on the application structure. [...] Easy, iterative adoption is definitely something in React’s favor for us.
|
||||
|
||||
### Storehouse
|
||||
[Storehouse](https://www.storehouse.co) (Apple Design Award 2014)'s web presence is build with React. Here's [an example story](https://www.storehouse.co/stories/y2ad-mexico-city-clouds). Congratulations on the award!
|
||||
|
||||
### Vim Awesome
|
||||
[Vim Awesome](http://vimawesome.com), an open-source Vim plugins directory built on React, was just launched. Be sure to [check out the source code](https://github.com/divad12/vim-awesome) if you're curious to see an example of how to build a small single-page React app.
|
||||
|
||||
## Random Tweets
|
||||
|
||||
<blockquote class="twitter-tweet" lang="en"><p>Spent 12 hours so far with <a href="https://twitter.com/hashtag/reactjs?src=hash">#reactjs</a>. Spent another 2 wondering why we've been doing JS frameworks wrong until now. React makes me happy.</p>— Paul Irwin (@paulirwin) <a href="https://twitter.com/paulirwin/statuses/481263947589242882">June 24, 2014</a></blockquote>
|
||||
147
docs/_posts/2014-07-13-react-v0.11-rc1.md
Normal file
147
docs/_posts/2014-07-13-react-v0.11-rc1.md
Normal file
@@ -0,0 +1,147 @@
|
||||
---
|
||||
title: React v0.11 RC
|
||||
layout: post
|
||||
author: Paul O’Shannessy
|
||||
---
|
||||
|
||||
It's that time again… we're just about ready to ship a new React release! v0.11 includes a wide array of bug fixes and features. We highlighted some of the most important changes below, along with the full changelog.
|
||||
|
||||
The release candidate is available for download from the CDN:
|
||||
|
||||
* **React**
|
||||
Dev build with warnings: <http://fb.me/react-0.11.0-rc1.js>
|
||||
Minified build for production: <http://fb.me/react-0.11.0-rc1.min.js>
|
||||
* **React with Add-Ons**
|
||||
Dev build with warnings: <http://fb.me/react-with-addons-0.11.0-rc1.js>
|
||||
Minified build for production: <http://fb.me/react-with-addons-0.11.0-rc1.min.js>
|
||||
* **In-Browser JSX transformer**
|
||||
<http://fb.me/JSXTransformer-0.11.0-rc1.js>
|
||||
|
||||
We've also published version `0.11.0-rc1` of the `react` and `react-tools` packages on npm and the `react` package on bower.
|
||||
|
||||
Please try these builds out and [file an issue on GitHub](https://github.com/facebook/react/issues/new) if you see anything awry.
|
||||
|
||||
|
||||
# Blog Post
|
||||
|
||||
## `getDefaultProps`
|
||||
|
||||
Starting in React 0.11, `getDefaultProps()` is called only once when `React.createClass()` is called, instead of each time a component is rendered. This means that `getDefaultProps()` can no longer vary its return value based on `this.props` and any objects will be shared across all instances. This change improves performance and will make it possible in the future to do PropTypes checks earlier in the rendering process, allowing us to give better error messages.
|
||||
|
||||
|
||||
## Rendering to `null`
|
||||
|
||||
Since React's release, people have been using work arounds to "render nothing". Usually this means returning an empty `<div/>` or `<span/>`. Some people even got clever and started returning `<noscript/>` to avoid extraneous DOM nodes. We finally provided a "blessed" solution that allows developers to writing meaningful code. Returning `null` in an explicit indication to React that you do not want anything rendered. Behind the scenes we make this work with a `<noscript>` element, though in the future we hope to not put anything in the document. In the mean time, `<noscript>` elements do not affect layout in any way, so you can feel safe using `null` today!
|
||||
|
||||
```js
|
||||
// Before
|
||||
render: function() {
|
||||
if (!this.state.visible) {
|
||||
return <span/>;
|
||||
}
|
||||
// ...
|
||||
}
|
||||
|
||||
// After
|
||||
render: function() {
|
||||
if (!this.state.visible) {
|
||||
return null;
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## JSX Namespacing
|
||||
|
||||
Another feature request we've been hearing for a long time is the ability to have namespaces in JSX. Given that JSX is just JavaScript, we didn't want to use XML namespacing. Instead we opted for a standard JS approach: object property access. Instead of assigning variables to access components stored in an object (such as a component library), you can now use the component directly as `<Namespace.Component/>`.
|
||||
|
||||
```js
|
||||
// Before
|
||||
var UI = require('UI');
|
||||
var UILayout = UI.Layout;
|
||||
var UIButton = UI.Button;
|
||||
var UILabel = UI.Label;
|
||||
|
||||
render: function() {
|
||||
return <UILayout><UIButton /><UILabel>text</UILabel></UILayout>;
|
||||
}
|
||||
|
||||
// After
|
||||
var UI = require('UI');
|
||||
|
||||
render: function() {
|
||||
return <UI.Layout><UI.Button /><UI.Label>text</UI.Label></UI.Layout>;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Improved keyboard event normalization
|
||||
|
||||
Keyboard events now contain a normalized `e.key` value according to the [DOM Level 3 Events spec](http://www.w3.org/TR/DOM-Level-3-Events/#keys-special), allowing you to write simpler key handling code that works in all browsers, such as:
|
||||
|
||||
```js
|
||||
handleKeyDown: function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
// Handle enter key
|
||||
} else if (e.key === ' ') {
|
||||
// Handle spacebar
|
||||
} else if (e.key === 'ArrowLeft') {
|
||||
// Handle left arrow
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
Keyboard and mouse events also now include a normalized `e.getModifierState()` that works consistently across browsers.
|
||||
|
||||
## Changelog
|
||||
|
||||
### React Core
|
||||
|
||||
#### Breaking Changes
|
||||
* `getDefaultProps()` is now called once per class and shared across all instances
|
||||
|
||||
#### New Features
|
||||
* Rendering to `null`
|
||||
* Keyboard events include normalized `e.key` and `e.getModifierState()` properties
|
||||
* New normalized `onBeforeInput` event
|
||||
* `React.Children.count` has been added as a helper for counting the number of children
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Re-renders are batched in more cases
|
||||
* Events: `e.view` properly normalized
|
||||
* Added Support for more HTML attributes (`coords`, `crossOrigin`, `download`, `hrefLang`, `mediaGroup`, `muted`, `scrolling`, `shape`, `srcSet`, `start`, `useMap`)
|
||||
* Improved SVG support
|
||||
* Changing `className` on a mounted SVG component now works correctly
|
||||
* Added support for elements `mask` and `tspan`
|
||||
* Added support for attributes `dx`, `dy`, `fillOpacity`, `fontFamily`, `fontSize`, `markerEnd`, `markerMid`, `markerStart`, `opacity`, `patternContentUnits`, `patternUnits`, `preserveAspectRatio`, `strokeDasharray`, `strokeOpacity`
|
||||
* CSS property names with vendor prefixes (`Webkit`, `ms`, `Moz`, `O`) are now handled properly
|
||||
* Duplicate keys no longer cause a hard error; now a warning is logged (and only one of the children with the same key is shown)
|
||||
* `img` event listeners are now unbound properly, preventing the error "Two valid but unequal nodes with the same `data-reactid`"
|
||||
* Added explicit warning when missing polyfills
|
||||
|
||||
### React With Addons
|
||||
* PureRenderMixin
|
||||
* Perf: a new set of tools to help with performance analysis
|
||||
* Update: New `$apply` command to transform values
|
||||
* TransitionGroup bug fixes with null elements, Android
|
||||
|
||||
### React NPM Module
|
||||
* Now includes the pre-built packages under `dist/`.
|
||||
* `envify` is properly listed as a dependency instead of a peer dependency
|
||||
|
||||
### JSX
|
||||
* Added support for namespaces, eg `<Components.Checkbox />`
|
||||
* JSXTransformer
|
||||
* Enable the same `harmony` features available in the command line with `<script type="text/jsx;harmony=true">`
|
||||
* Scripts are downloaded in parallel for more speed. They are still executed in order (as you would expect with normal script tags)
|
||||
* Fixed a bug preventing sourcemaps from working in Firefox
|
||||
|
||||
### React Tools Module
|
||||
* Improved readme with usage and API information
|
||||
* Improved ES6 transforms available with `--harmony` option
|
||||
* Added `--source-map-inline` option to the `jsx` executable
|
||||
* New `transformWithDetails` API which gives access to the raw sourcemap data
|
||||
|
||||
|
||||
127
docs/acknowledgements.md
Normal file
127
docs/acknowledgements.md
Normal file
@@ -0,0 +1,127 @@
|
||||
---
|
||||
id: acknowledgements
|
||||
title: Acknowledgements
|
||||
layout: single
|
||||
---
|
||||
|
||||
We'd like to thank all of our contributors:
|
||||
|
||||
<div class="three-column">
|
||||
<ul>
|
||||
<li>Alan deLevie</li>
|
||||
<li>Alex Zelenskiy</li>
|
||||
<li>Alexander Solovyov</li>
|
||||
<li>Andreas Svensson</li>
|
||||
<li>Andrew Davey</li>
|
||||
<li>Andrew Zich</li>
|
||||
<li>Andrey Popp</li>
|
||||
<li>Ayman Osman</li>
|
||||
<li>Ben Alpert</li>
|
||||
<li>Ben Newman</li>
|
||||
<li>Ben Ripkens</li>
|
||||
<li>Bob Eagan</li>
|
||||
<li>Brian Cooke</li>
|
||||
<li>Brian Kim</li>
|
||||
<li>Brian Rue</li>
|
||||
<li>Cam Spiers</li>
|
||||
<li>Cat Chen</li>
|
||||
<li>Cheng Lou</li>
|
||||
<li>Christian Roman</li>
|
||||
<li>Christoph Pojer</li>
|
||||
<li>Clay Allsopp</li>
|
||||
<li>Connor McSheffrey</li>
|
||||
<li>Dan Schafer</li>
|
||||
<li>Daniel Gasienica</li>
|
||||
<li>Daniel Lo Nigro</li>
|
||||
<li>Daniel Miladinov</li>
|
||||
<li>Danny Ben-David</li>
|
||||
<li>David Hellsing</li>
|
||||
<li>David Hu</li>
|
||||
<li>Dustin Getz</li>
|
||||
<li>Eric Clemmons</li>
|
||||
<li>Eric Schoffstall</li>
|
||||
<li>Fabio M. Costa</li>
|
||||
<li>Felipe Oliveira Carvalho</li>
|
||||
<li>Felix Kling</li>
|
||||
<li>Fernando Correia</li>
|
||||
<li>Greg Roodt</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Guido Bouman</li>
|
||||
<li>Harry Hull</li>
|
||||
<li>Hugo Jobling</li>
|
||||
<li>Ian Obermiller</li>
|
||||
<li>Ingvar Stepanyan</li>
|
||||
<li>Isaac Salier-Hellendag</li>
|
||||
<li>Ivan Kozik</li>
|
||||
<li>Jakub Malinowski</li>
|
||||
<li>James Ide</li>
|
||||
<li>Jamie Wong</li>
|
||||
<li>Jamison Dance</li>
|
||||
<li>Jan Kassens</li>
|
||||
<li>Jared Forsyth</li>
|
||||
<li>Jason Bonta</li>
|
||||
<li>Jason Trill</li>
|
||||
<li>Jean Lauliac</li>
|
||||
<li>Jeff Morrison</li>
|
||||
<li>Jeffrey Lin</li>
|
||||
<li>Jignesh Kakadiya</li>
|
||||
<li>Johannes Baiter</li>
|
||||
<li>John Watson</li>
|
||||
<li>Jonas Gebhardt</li>
|
||||
<li>Jonathan Hsu</li>
|
||||
<li>Jordan Walke</li>
|
||||
<li>Josh Duck</li>
|
||||
<li>Jun Wu</li>
|
||||
<li>Keito Uchiyama</li>
|
||||
<li>Kit Randel</li>
|
||||
<li>Kunal Mehta</li>
|
||||
<li>Laurence Rowe</li>
|
||||
<li>Levi McCallum</li>
|
||||
<li>Logan Allen</li>
|
||||
<li>Luigy Leon</li>
|
||||
<li>Mark Richardson</li>
|
||||
<li>Marshall Roch</li>
|
||||
<li>Martin Andert</li>
|
||||
<li>Martin Konicek</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Mathieu M-Gosselin</li>
|
||||
<li>Matt Harrison</li>
|
||||
<li>Matti Nelimarkka</li>
|
||||
<li>Michal Srb</li>
|
||||
<li>Mouad Debbar</li>
|
||||
<li>Nadeesha Cabral</li>
|
||||
<li>Nicholas Bergson-Shilcock</li>
|
||||
<li>Nick Gavalas</li>
|
||||
<li>Nick Thompson</li>
|
||||
<li>Owen Coutts</li>
|
||||
<li>Pascal Hartig</li>
|
||||
<li>Paul O’Shannessy</li>
|
||||
<li>Paul Seiffert</li>
|
||||
<li>Paul Shen</li>
|
||||
<li>Pete Hunt</li>
|
||||
<li>Peter Cottle</li>
|
||||
<li>Petri Lievonen</li>
|
||||
<li>Pieter Vanderwerff</li>
|
||||
<li>Richard D. Worth</li>
|
||||
<li>Richard Feldman</li>
|
||||
<li>Richard Livesey</li>
|
||||
<li>Sander Spies</li>
|
||||
<li>Sean Kinsey</li>
|
||||
<li>Sebastian Markbåge</li>
|
||||
<li>Shaun Trennery</li>
|
||||
<li>Simon Højberg</li>
|
||||
<li>Stoyan Stefanov</li>
|
||||
<li>Sundeep Malladi</li>
|
||||
<li>Thomas Aylott</li>
|
||||
<li>Timothy Yung</li>
|
||||
<li>Tom Occhino</li>
|
||||
<li>Vjeux</li>
|
||||
<li>Wincent Colaiuta</li>
|
||||
<li>Zach Bruggeman</li>
|
||||
<li>imagentleman</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
In addition, we're grateful to [Jeff Barczewski](https://github.com/jeffbski) for allowing us to use the [react](https://www.npmjs.org/package/react) package name on npm and to [Christopher Aue](http://christopheraue.net/) for letting us use the [reactjs.com](http://reactjs.com/) domain name and the [@reactjs](https://twitter.com/reactjs) username on Twitter.
|
||||
@@ -20,7 +20,7 @@ sectionid: blog
|
||||
|
||||
<div class="pagination">
|
||||
{% if paginator.previous_page %}
|
||||
<a href="/react/{{ paginator.previous_page_path }}" class="previous">
|
||||
<a href="/react{{ paginator.previous_page_path }}" class="previous">
|
||||
« Previous Page
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
@@ -19,7 +19,7 @@ Let's look at a really simple example. Create a `hello-react.html` file with the
|
||||
<html>
|
||||
<head>
|
||||
<title>Hello React</title>
|
||||
<script src="http://fb.me/react-{{site.react_version}}.min.js"></script>
|
||||
<script src="http://fb.me/react-{{site.react_version}}.js"></script>
|
||||
<script src="http://fb.me/JSXTransformer-{{site.react_version}}.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -84,8 +84,8 @@ We've found that the best solution for this problem is to generate markup direct
|
||||
|
||||
**JSX lets you write JavaScript function calls with HTML syntax.** To generate a link in React using pure JavaScript you'd write: `React.DOM.a({href: 'http://facebook.github.io/react/'}, 'Hello React!')`. With JSX this becomes `<a href="http://facebook.github.io/react/">Hello React!</a>`. We've found this has made building React apps easier and designers tend to prefer the syntax, but everyone has their own workflow, so **JSX is not required to use React.**
|
||||
|
||||
JSX is very small; the "hello, world" example above uses every feature of JSX. To learn more about it, see [JSX in depth](./jsx-in-depth.html). Or see the transform in action in [our live JSX compiler](/react/jsx-compiler.html).
|
||||
JSX is very small; the "hello, world" example above uses every feature of JSX. To learn more about it, see [JSX in depth](/react/docs/jsx-in-depth.html). Or see the transform in action in [our live JSX compiler](/react/jsx-compiler.html).
|
||||
|
||||
JSX is similar to HTML, but not exactly the same. See [JSX gotchas](./jsx-gotchas.html) for some key differences.
|
||||
JSX is similar to HTML, but not exactly the same. See [JSX gotchas](/react/docs/jsx-gotchas.html) for some key differences.
|
||||
|
||||
The easiest way to get started with JSX is to use the in-browser `JSXTransformer`. We strongly recommend that you don't use this in production. You can precompile your code using our command-line [react-tools](http://npmjs.org/package/react-tools) package.
|
||||
|
||||
@@ -10,6 +10,11 @@ next: jsx-gotchas.html
|
||||
JSX is a JavaScript XML syntax transform recommended for use
|
||||
with React.
|
||||
|
||||
> Note:
|
||||
>
|
||||
> Don't forget the `/** @jsx React.DOM */` pragma at the beginning of your file! This tells JSX to process the file for React.
|
||||
>
|
||||
> If you don't include the pragma, your source will remain untouched, so it's safe to run the JSX transformer on all JS files in your codebase if you want to.
|
||||
|
||||
## Why JSX?
|
||||
|
||||
@@ -53,9 +58,11 @@ var app = Nav({color:"blue"}, Profile(null, "click"));
|
||||
```
|
||||
|
||||
Use the [JSX Compiler](/react/jsx-compiler.html) to try out JSX and see how it
|
||||
desugars into native JavaScript.
|
||||
desugars into native JavaScript, and the
|
||||
[HTML to JSX converter](/react/html-jsx.html) to convert your existing HTML to
|
||||
JSX.
|
||||
|
||||
If you want to use JSX, the [Getting Started](getting-started.html) guide shows
|
||||
If you want to use JSX, the [Getting Started](/react/docs/getting-started.html) guide shows
|
||||
how to setup compilation.
|
||||
|
||||
> Note:
|
||||
@@ -92,7 +99,10 @@ var MyComponent = React.createClass({/*...*/});
|
||||
var app = <MyComponent someProperty={true} />;
|
||||
```
|
||||
|
||||
See [Multiple Components](multiple-components.html) to learn more about using composite components.
|
||||
JSX will infer the component's name from the variable assignment and specify
|
||||
the class's [displayName](/react/docs/component-specs.html#displayName) accordingly.
|
||||
|
||||
See [Multiple Components](/react/docs/multiple-components.html) to learn more about using composite components.
|
||||
|
||||
> Note:
|
||||
>
|
||||
@@ -151,10 +161,20 @@ var content = Container(null, window.isLoggedIn ? Nav(null) : Login(null));
|
||||
|
||||
### Comments
|
||||
|
||||
It's easy to add comments within your JSX; they're just JS expressions:
|
||||
It's easy to add comments within your JSX; they're just JS expressions. You just need to be careful to put `{}` around the comments when you are within the children section of a tag.
|
||||
|
||||
```javascript
|
||||
var content = <Container>{/* this is a comment */}<Nav /></Container>;
|
||||
var content = (
|
||||
<Nav>
|
||||
{/* child comment, put {} around */}
|
||||
<Person
|
||||
/* multi
|
||||
line
|
||||
comment */
|
||||
name={window.isLoggedIn ? window.name : ''} // end of line comment
|
||||
/>
|
||||
</Nav>
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
@@ -168,4 +188,4 @@ efforts include:
|
||||
* JSX neither provides nor requires a runtime library.
|
||||
* JSX does not alter or add to the semantics of JavaScript.
|
||||
|
||||
JSX is similar to HTML, but not exactly the same. See [JSX gotchas](./jsx-gotchas.html) for some key differences.
|
||||
JSX is similar to HTML, but not exactly the same. See [JSX gotchas](/react/docs/jsx-gotchas.html) for some key differences.
|
||||
|
||||
@@ -11,18 +11,7 @@ JSX looks like HTML but there are some important differences you may run into.
|
||||
|
||||
> Note:
|
||||
>
|
||||
> For DOM differences, such as the inline `style` attribute, check [here](dom-differences.html).
|
||||
|
||||
## Whitespace Removal
|
||||
|
||||
JSX doesn't follow the same whitespace elimination rules as HTML. JSX removes all whitespace between two curly braces expressions. If you want to have whitespace, simply add `{' '}`.
|
||||
|
||||
```javascript
|
||||
<div>{this.props.name} {' '} {this.props.surname}</div>
|
||||
```
|
||||
|
||||
Follow [Issue #65](https://github.com/facebook/react/issues/65) for discussion on this behavior.
|
||||
|
||||
> For DOM differences, such as the inline `style` attribute, check [here](/react/docs/dom-differences.html).
|
||||
|
||||
## HTML Entities
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ prev: jsx-gotchas.html
|
||||
next: multiple-components.html
|
||||
---
|
||||
|
||||
You've already [learned how to display data](./displaying-data.html) with React. Now let's look at how to make our UIs interactive.
|
||||
You've already [learned how to display data](/react/docs/displaying-data.html) with React. Now let's look at how to make our UIs interactive.
|
||||
|
||||
|
||||
## A Simple Example
|
||||
|
||||
@@ -73,7 +73,7 @@ When you create a React component instance, you can include additional React com
|
||||
<Parent><Child /></Parent>
|
||||
```
|
||||
|
||||
`Parent` can read its children by accessing the special `this.props.children` prop.
|
||||
`Parent` can read its children by accessing the special `this.props.children` prop. **`this.props.children` is an opaque data structure:** use the [React.Children utilities](/react/docs/top-level-api.html#react.children) to manipulate them.
|
||||
|
||||
|
||||
### Child Reconciliation
|
||||
@@ -124,7 +124,7 @@ The situation gets more complicated when the children are shuffled around (as in
|
||||
var results = this.props.results;
|
||||
return (
|
||||
<ol>
|
||||
{this.results.map(function(result) {
|
||||
{results.map(function(result) {
|
||||
return <li key={result.id}>{result.text}</li>;
|
||||
})}
|
||||
</ol>
|
||||
@@ -134,6 +134,26 @@ The situation gets more complicated when the children are shuffled around (as in
|
||||
|
||||
When React reconciles the keyed children, it will ensure that any child with `key` will be reordered (instead of clobbered) or destroyed (instead of reused).
|
||||
|
||||
You can also key children by passing an object. The object keys will be used as `key` for each value. However it is important to remember that JavaScript does not guarantee the ordering of properties will be preserved. In practice browsers will preserve property order **except** for properties that can be parsed as a 32-bit unsigned integers. Numeric properties will be ordered sequentially and before other properties. If this happens React will render components out of order. This can be avoided by adding a string prefix to the key:
|
||||
|
||||
```javascript
|
||||
render: function() {
|
||||
var items = {};
|
||||
|
||||
this.props.results.forEach(function(result) {
|
||||
// If result.id can look like a number (consider short hashes), then
|
||||
// object iteration order is not guaranteed. In this case, we add a prefix
|
||||
// to ensure the keys are strings.
|
||||
items['result-' + result.id] = <li>{result.text}</li>;
|
||||
});
|
||||
|
||||
return (
|
||||
<ol>
|
||||
{items}
|
||||
</ol>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Data Flow
|
||||
|
||||
@@ -144,7 +164,7 @@ In React, data flows from owner to owned component through `props` as discussed
|
||||
|
||||
You may be thinking that it's expensive to react to changing data if there are a large number of nodes under an owner. The good news is that JavaScript is fast and `render()` methods tend to be quite simple, so in most applications this is extremely fast. Additionally, the bottleneck is almost always the DOM mutation and not JS execution and React will optimize this for you using batching and change detection.
|
||||
|
||||
However, sometimes you really want to have fine-grained control over your performance. In that case, simply override `shouldComponentUpdate()` to return false when you want React to skip processing of a subtree. See [the React reference docs](component-specs.html) for more information.
|
||||
However, sometimes you really want to have fine-grained control over your performance. In that case, simply override `shouldComponentUpdate()` to return false when you want React to skip processing of a subtree. See [the React reference docs](/react/docs/component-specs.html) for more information.
|
||||
|
||||
> Note:
|
||||
>
|
||||
|
||||
@@ -12,7 +12,7 @@ When designing interfaces, break down the common design elements (buttons, form
|
||||
|
||||
## Prop Validation
|
||||
|
||||
As your app grows it's helpful to ensure that your components are used correctly. We do this by allowing you to specify `propTypes`. `React.PropTypes` exports a range of validators that can be used to make sure the data you receive is valid. When an invalid value is provided for a prop, an error will be thrown. Here is an example documenting the different validators provided:
|
||||
As your app grows it's helpful to ensure that your components are used correctly. We do this by allowing you to specify `propTypes`. `React.PropTypes` exports a range of validators that can be used to make sure the data you receive is valid. When an invalid value is provided for a prop, a warning will be shown in the JavaScript console. Note that for performance reasons `propTypes` is only checked in development mode. Here is an example documenting the different validators provided:
|
||||
|
||||
```javascript
|
||||
React.createClass({
|
||||
@@ -26,22 +26,48 @@ React.createClass({
|
||||
optionalObject: React.PropTypes.object,
|
||||
optionalString: React.PropTypes.string,
|
||||
|
||||
// You can ensure that your prop is limited to specific values by treating
|
||||
// it as an enum.
|
||||
optionalEnum: React.PropTypes.oneOf(['News','Photos']),
|
||||
// Anything that can be rendered: numbers, strings, components or an array
|
||||
// containing these types.
|
||||
optionalRenderable: React.PropTypes.renderable,
|
||||
|
||||
// A React component.
|
||||
optionalComponent: React.PropTypes.component,
|
||||
|
||||
// You can also declare that a prop is an instance of a class. This uses
|
||||
// JS's instanceof operator.
|
||||
someClass: React.PropTypes.instanceOf(SomeClass),
|
||||
optionalMessage: React.PropTypes.instanceOf(Message),
|
||||
|
||||
// You can chain any of the above with isRequired to make sure an error is
|
||||
// thrown if the prop isn't provided.
|
||||
requiredFunc: React.PropTypes.func.isRequired
|
||||
// You can ensure that your prop is limited to specific values by treating
|
||||
// it as an enum.
|
||||
optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
|
||||
|
||||
// An object that could be one of many types
|
||||
optionalUnion: React.PropTypes.oneOfType([
|
||||
React.PropTypes.string,
|
||||
React.PropTypes.number,
|
||||
React.PropTypes.instanceOf(Message)
|
||||
]),
|
||||
|
||||
// An array of a certain type
|
||||
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
|
||||
|
||||
// An object taking on a particular shape
|
||||
optionalObjectWithShape: React.PropTypes.shape({
|
||||
color: React.PropTypes.string,
|
||||
fontSize: React.PropTypes.number
|
||||
}),
|
||||
|
||||
// You can chain any of the above with isRequired to make sure a warning is
|
||||
// shown if the prop isn't provided.
|
||||
requiredFunc: React.PropTypes.func.isRequired,
|
||||
|
||||
// A value of any data type
|
||||
requiredAny: React.PropTypes.any.isRequired,
|
||||
|
||||
// You can also specify a custom validator.
|
||||
customProp: function(props, propName, componentName) {
|
||||
if (!/matchme/.test(props[propName])) {
|
||||
throw new Error('Validation failed!')
|
||||
console.warn('Validation failed!');
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -91,12 +117,32 @@ React.renderComponent(
|
||||
);
|
||||
```
|
||||
|
||||
## Single Child
|
||||
|
||||
With `React.PropTypes.component` you can specify that only a single child can be passed to
|
||||
a component as children.
|
||||
|
||||
```javascript
|
||||
var MyComponent = React.createClass({
|
||||
propTypes: {
|
||||
children: React.PropTypes.component.isRequired
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return
|
||||
<div>
|
||||
{this.props.children} // This must be exactly one element or it will throw.
|
||||
</div>;
|
||||
}
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
## Mixins
|
||||
|
||||
Components are the best way to reuse code in React, but sometimes very different components may share some common functionality. These are sometimes called [cross-cutting concerns](http://en.wikipedia.org/wiki/Cross-cutting_concern). React provides `mixins` to solve this problem.
|
||||
|
||||
One common use case is a component wanting to update itself on a time interval. It's easy to use `setInterval()`, but it's important to cancel your interval when you don't need it anymore to save memory. React provides [lifecycle methods](./working-with-the-browser.html) that let you know when a component is about to be created or destroyed. Let's create a simple mixin that uses these methods to provide an easy `setInterval()` function that will automatically get cleaned up when your component is destroyed.
|
||||
One common use case is a component wanting to update itself on a time interval. It's easy to use `setInterval()`, but it's important to cancel your interval when you don't need it anymore to save memory. React provides [lifecycle methods](/react/docs/working-with-the-browser.html#component-lifecycle) that let you know when a component is about to be created or destroyed. Let's create a simple mixin that uses these methods to provide an easy `setInterval()` function that will automatically get cleaned up when your component is destroyed.
|
||||
|
||||
```javascript
|
||||
/** @jsx React.DOM */
|
||||
|
||||
@@ -9,6 +9,7 @@ next: working-with-the-browser.html
|
||||
|
||||
Form components such as `<input>`, `<textarea>`, and `<option>` differ from other native components because they can be mutated via user interactions. These components provide interfaces that make it easier to manage forms in response to user interactions.
|
||||
|
||||
For information on events on `<form>` see [Form Events](/react/docs/events.html#form-events).
|
||||
|
||||
## Interactive Props
|
||||
|
||||
@@ -87,7 +88,7 @@ If you want to initialize the component with a non-empty value, you can supply a
|
||||
|
||||
This example will function much like the **Controlled Components** example above.
|
||||
|
||||
Likewise, `<input>` supports `defaultChecked` and `<option>` supports `defaultSelected`.
|
||||
Likewise, `<input>` supports `defaultChecked` and `<select>` supports `defaultValue`.
|
||||
|
||||
|
||||
## Advanced Topics
|
||||
|
||||
@@ -10,7 +10,7 @@ next: more-about-refs.html
|
||||
React provides powerful abstractions that free you from touching the DOM directly in most cases, but sometimes you simply need to access the underlying API, perhaps to work with a third-party library or existing code.
|
||||
|
||||
|
||||
## The Mock DOM
|
||||
## The Virtual DOM
|
||||
|
||||
React is so fast because it never talks to the DOM directly. React maintains a fast in-memory representation of the DOM. `render()` methods return a *description* of the DOM, and React can diff this description with the in-memory representation to compute the fastest way to update the browser.
|
||||
|
||||
@@ -62,7 +62,7 @@ React.renderComponent(
|
||||
|
||||
## More About Refs
|
||||
|
||||
To learn more about refs, including ways to use them effectively, see our [more about refs](./more-about-refs.html) documentation.
|
||||
To learn more about refs, including ways to use them effectively, see our [more about refs](/react/docs/more-about-refs.html) documentation.
|
||||
|
||||
|
||||
## Component Lifecycle
|
||||
@@ -80,7 +80,7 @@ React provides lifecycle methods that you can specify to hook into this process.
|
||||
|
||||
* `getInitialState(): object` is invoked before a component is mounted. Stateful components should implement this and return the initial state data.
|
||||
* `componentWillMount()` is invoked immediately before mounting occurs.
|
||||
* `componentDidMount(DOMElement rootNode)` is invoked immediately after mounting occurs. Initialization that requires DOM nodes should go here.
|
||||
* `componentDidMount()` is invoked immediately after mounting occurs. Initialization that requires DOM nodes should go here.
|
||||
|
||||
|
||||
### Updating
|
||||
@@ -88,7 +88,7 @@ React provides lifecycle methods that you can specify to hook into this process.
|
||||
* `componentWillReceiveProps(object nextProps)` is invoked when a mounted component receives new props. This method should be used to compare `this.props` and `nextProps` to perform state transitions using `this.setState()`.
|
||||
* `shouldComponentUpdate(object nextProps, object nextState): boolean` is invoked when a component decides whether any changes warrant an update to the DOM. Implement this as an optimization to compare `this.props` with `nextProps` and `this.state` with `nextState` and return false if React should skip updating.
|
||||
* `componentWillUpdate(object nextProps, object nextState)` is invoked immediately before updating occurs. You cannot call `this.setState()` here.
|
||||
* `componentDidUpdate(object prevProps, object prevState, DOMElement rootNode)` is invoked immediately after updating occurs.
|
||||
* `componentDidUpdate(object prevProps, object prevState)` is invoked immediately after updating occurs.
|
||||
|
||||
|
||||
### Unmounting
|
||||
@@ -103,12 +103,6 @@ _Mounted_ composite components also support the following methods:
|
||||
* `getDOMNode(): DOMElement` can be invoked on any mounted component in order to obtain a reference to its rendered DOM node.
|
||||
* `forceUpdate()` can be invoked on any mounted component when you know that some deeper aspect of the component's state has changed without using `this.setState()`.
|
||||
|
||||
> Note:
|
||||
>
|
||||
> The `DOMElement rootNode` argument of `componentDidMount()` and
|
||||
> `componentDidUpdate()` is a convenience. The same node can be obtained by
|
||||
> calling `this.getDOMNode()`.
|
||||
|
||||
|
||||
## Browser Support and Polyfills
|
||||
|
||||
@@ -119,7 +113,7 @@ In addition to that philosophy, we've also taken the stance that we, as authors
|
||||
|
||||
### Polyfills Needed to Support Older Browsers
|
||||
|
||||
These six functions can be polyfilled using `es5-shim.js` from [kriskowal's es5-shim](https://github.com/kriskowal/es5-shim):
|
||||
`es5-shim.js` from [kriskowal's es5-shim](https://github.com/kriskowal/es5-shim) provides the following that React needs:
|
||||
|
||||
* `Array.isArray`
|
||||
* `Array.prototype.forEach`
|
||||
@@ -127,8 +121,28 @@ These six functions can be polyfilled using `es5-shim.js` from [kriskowal's es5-
|
||||
* `Array.prototype.some`
|
||||
* `Date.now`
|
||||
* `Function.prototype.bind`
|
||||
* `Object.keys`
|
||||
|
||||
Other required polyfills:
|
||||
`es5-sham.js`, also from [kriskowal's es5-shim](https://github.com/kriskowal/es5-shim), provides the following that React needs:
|
||||
|
||||
* `Object.create` – Provided by `es5-sham.js` from [kriskowal's es5-shim](https://github.com/kriskowal/es5-shim).
|
||||
* `console.*` – Only needed when using the unminified build. If you need to polyfill this, try [paulmillr's console-polyfill](https://github.com/paulmillr/console-polyfill).
|
||||
* `Object.create`
|
||||
* `Object.freeze`
|
||||
|
||||
The unminified build of React needs the following from [paulmillr's console-polyfill](https://github.com/paulmillr/console-polyfill).
|
||||
|
||||
* `console.*`
|
||||
|
||||
When using HTML5 elements in IE8 including `<section>`, `<article>`, `<nav>`, `<header>`, and `<footer>`, it's also necessary to include [html5shiv](https://github.com/aFarkas/html5shiv) or a similar script.
|
||||
|
||||
|
||||
### Cross-browser Issues
|
||||
|
||||
Although React is pretty good at abstracting browser differences, some browsers are limited or present quirky behaviors that we couldn't find a workaround for.
|
||||
|
||||
|
||||
#### onScroll event on IE8
|
||||
|
||||
On IE8 the `onScroll` event doesn't bubble and IE8 doesn't have an API to define handlers to the capturing phase of an event, meaning there is no way for React to listen to these events.
|
||||
Currently a handler to this event is ignored on IE8.
|
||||
|
||||
See the [onScroll doesn't work in IE8](https://github.com/facebook/react/issues/631) GitHub issue for more information.
|
||||
|
||||
@@ -15,7 +15,7 @@ Consider the case when you wish to tell an `<input />` element (that exists with
|
||||
getInitialState: function() {
|
||||
return {userInput: ''};
|
||||
},
|
||||
handleKeyUp: function(e) {
|
||||
handleChange: function(e) {
|
||||
this.setState({userInput: e.target.value});
|
||||
},
|
||||
clearAndFocusInput: function() {
|
||||
@@ -26,11 +26,11 @@ Consider the case when you wish to tell an `<input />` element (that exists with
|
||||
return (
|
||||
<div>
|
||||
<div onClick={this.clearAndFocusInput}>
|
||||
Click To Focus and Reset
|
||||
Click to Focus and Reset
|
||||
</div>
|
||||
<input
|
||||
value={this.state.userInput}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -72,17 +72,19 @@ React supports a very special property that you can attach to any component that
|
||||
|
||||
It's as simple as:
|
||||
|
||||
**1.** Assign a `ref` attribute to anything returned from `render` such as:
|
||||
1. Assign a `ref` attribute to anything returned from `render` such as:
|
||||
|
||||
```html
|
||||
<input ref="myInput" />
|
||||
```
|
||||
```html
|
||||
<input ref="myInput" />
|
||||
```
|
||||
|
||||
**2.** In some other code (typically event handler code), access the **backing instance** via `this.refs` as in:
|
||||
2. In some other code (typically event handler code), access the **backing instance** via `this.refs` as in:
|
||||
|
||||
```javascript
|
||||
```javascript
|
||||
this.refs.myInput
|
||||
```
|
||||
```
|
||||
|
||||
You can access the component's DOM node directly by calling `this.refs.myInput.getDOMNode()`.
|
||||
|
||||
## Completing the Example
|
||||
|
||||
@@ -91,23 +93,26 @@ It's as simple as:
|
||||
getInitialState: function() {
|
||||
return {userInput: ''};
|
||||
},
|
||||
handleKeyUp: function(e) {
|
||||
handleChange: function(e) {
|
||||
this.setState({userInput: e.target.value});
|
||||
},
|
||||
clearAndFocusInput: function() {
|
||||
this.setState({userInput: ''}); // Clear the input
|
||||
this.refs.theInput.getDOMNode().focus(); // Boom! Focused!
|
||||
// Clear the input
|
||||
this.setState({userInput: ''}, function() {
|
||||
// This code executes after the component is re-rendered
|
||||
this.refs.theInput.getDOMNode().focus(); // Boom! Focused!
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<div onClick={this.clearAndFocusInput}>
|
||||
Click To Focus and Reset
|
||||
Click to Focus and Reset
|
||||
</div>
|
||||
<input
|
||||
ref="theInput"
|
||||
value={this.state.userInput}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -132,4 +137,4 @@ Refs are a great way to send a message to a particular child instance in a way t
|
||||
|
||||
- *Never* access refs inside of any component's render method - or while any component's render method is even running anywhere in the call stack.
|
||||
- If you want to preserve Google Closure Compiler Crushing resilience, make sure to never access as a property what was specified as a string. This means you must access using `this.refs['myRefString']` if your ref was defined as `ref="myRefString"`.
|
||||
- If you have not programmed several apps with React, your first inclination is usually going to be to try to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where `state` should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy. Placing the state there often eliminates any desire to use `ref`s to "make things happen" - instead, the data flow will usually accomplish your goal.
|
||||
- If you have not programmed several apps with React, your first inclination is usually going to be to try to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where `state` should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy. Placing the state there often eliminates any desire to use `ref`s to "make things happen" – instead, the data flow will usually accomplish your goal.
|
||||
|
||||
@@ -38,23 +38,4 @@ If you have [npm](http://npmjs.org/), you can simply run `npm install -g react-t
|
||||
|
||||
### Helpful Open-Source Projects
|
||||
|
||||
The open-source community has built tools that integrate JSX with several build systems.
|
||||
|
||||
* [reactify](https://github.com/andreypopp/reactify) - use JSX with [browserify](http://browserify.org/)
|
||||
* [grunt-react](https://github.com/ericclemmons/grunt-react) - [grunt](http://gruntjs.com/) task for JSX
|
||||
* [require-jsx](https://github.com/seiffert/require-jsx) - use JSX with [require.js](http://requirejs.org/)
|
||||
* [pyReact](https://github.com/facebook/react-python) - use JSX with [Python](http://www.python.org/)
|
||||
* [react-rails](https://github.com/facebook/react-rails) - use JSX with [Ruby on Rails](http://rubyonrails.org/)
|
||||
|
||||
|
||||
### Syntax Highlighting & Linting
|
||||
|
||||
* Many editors already include reasonable support for JSX (Vim, Emacs js2-mode).
|
||||
* [JSX syntax highlighting](https://github.com/yungsters/sublime/blob/master/tmLanguage/JavaScript%20(JSX\).tmLanguage) is available for Sublime Text and other editors
|
||||
that support `*.tmLanguage`.
|
||||
* Linting provides accurate line numbers after compiling without sourcemaps.
|
||||
* Elements use standard scoping so linters can find usage of out-of-scope components.
|
||||
|
||||
## React Page
|
||||
|
||||
To get started on a new project, you can use [react-page](https://github.com/facebook/react-page/), a complete React project creator. It supports both server-side and client-side rendering, source transform and packaging JSX files using CommonJS modules, and instant reload.
|
||||
The open-source community has built tools that integrate JSX with several editors and build systems. See [JSX integrations](https://github.com/facebook/react/wiki/Complementary-Tools#jsx-integrations) for the full list.
|
||||
|
||||
@@ -9,8 +9,11 @@ next: animation.html
|
||||
|
||||
`React.addons` is where we park some useful utilities for building React apps. **These should be considered experimental** but will eventually be rolled into core or a blessed utilities library:
|
||||
|
||||
- `ReactTransitions`, for dealing with animations and transitions that are usually not simple to implement, such as before a component's removal.
|
||||
- `ReactLink`, to simplify the coordination between user's form input data and and the component's state.
|
||||
- `classSet`, for manipulating the DOM `class` string a bit more cleanly.
|
||||
- [`ReactTransitions`](animation.html), for dealing with animations and transitions that are usually not simple to implement, such as before a component's removal.
|
||||
- [`ReactLink`](two-way-binding-helpers.html), to simplify the coordination between user's form input data and and the component's state.
|
||||
- [`classSet()`](class-name-manipulation.html), for manipulating the DOM `class` string a bit more cleanly.
|
||||
- [`ReactTestUtils`](test-utils.html), simple helpers for writing test cases (unminified build only).
|
||||
- [`cloneWithProps()`](clone-with-props.html), to make shallow copies of React components and change their props.
|
||||
- [`update()`](update.html), a helper function that makes dealing with immutable data in JavaScript easier.
|
||||
|
||||
To get the add-ons, use `react-with-addons.js` (and its minified counterpart) rather than the common `react.js`.
|
||||
|
||||
@@ -7,16 +7,20 @@ prev: addons.html
|
||||
next: two-way-binding-helpers.html
|
||||
---
|
||||
|
||||
`ReactTransitions` is an easy way to perform CSS transitions and animations when a React component enters or leaves the DOM. It's inspired by the excellent [ng-animate](http://www.nganimate.org/) library.
|
||||
React provides a `ReactTransitionGroup` addon component as a low-level API for animation, and a `ReactCSSTransitionGroup` for easily implementing basic CSS animations and transitions.
|
||||
|
||||
## Getting Started
|
||||
## High-level API: `ReactCSSTransitionGroup`
|
||||
|
||||
`ReactTransitionGroup` is the interface to `ReactTransitions`. This is a simple element that wraps all of the components you are interested in animating. Here's an example where we fade list items in and out.
|
||||
`ReactCSSTransitionGroup` is based on `ReactTransitionGroup` and is an easy way to perform CSS transitions and animations when a React component enters or leaves the DOM. It's inspired by the excellent [ng-animate](http://www.nganimate.org/) library.
|
||||
|
||||
```javascript{22-24}
|
||||
### Getting Started
|
||||
|
||||
`ReactCSSTransitionGroup` is the interface to `ReactTransitions`. This is a simple element that wraps all of the components you are interested in animating. Here's an example where we fade list items in and out.
|
||||
|
||||
```javascript{30-32}
|
||||
/** @jsx React.DOM */
|
||||
|
||||
var ReactTransitionGroup = React.addons.TransitionGroup;
|
||||
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
|
||||
|
||||
var TodoList = React.createClass({
|
||||
getInitialState: function() {
|
||||
@@ -29,30 +33,30 @@ var TodoList = React.createClass({
|
||||
},
|
||||
handleRemove: function(i) {
|
||||
var newItems = this.state.items;
|
||||
newItems.splice(i, 1)
|
||||
newItems.splice(i, 1);
|
||||
this.setState({items: newItems});
|
||||
},
|
||||
render: function() {
|
||||
var items = this.state.items.map(function(item, i) {
|
||||
return (
|
||||
<div key={i} onClick={this.handleRemove.bind(this, i)}>
|
||||
<div key={item} onClick={this.handleRemove.bind(this, i)}>
|
||||
{item}
|
||||
</div>
|
||||
);
|
||||
}.bind(this));
|
||||
return (
|
||||
<div>
|
||||
<div><button onClick={this.handleAdd} /></div>
|
||||
<ReactTransitionGroup transitionName="example">
|
||||
<button onClick={this.handleAdd}>Add Item</button>
|
||||
<ReactCSSTransitionGroup transitionName="example">
|
||||
{items}
|
||||
</ReactTransitionGroup>
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
In this component, when a new item is added to `ReactTransitionGroup` it will get the `example-enter` CSS class and the `example-enter-active` CSS class added in the next tick. This is a convention based on the `transitionName` prop.
|
||||
In this component, when a new item is added to `ReactCSSTransitionGroup` it will get the `example-enter` CSS class and the `example-enter-active` CSS class added in the next tick. This is a convention based on the `transitionName` prop.
|
||||
|
||||
You can use these classes to trigger a CSS animation or transition. For example, try adding this CSS and adding a new list item:
|
||||
|
||||
@@ -67,7 +71,7 @@ You can use these classes to trigger a CSS animation or transition. For example,
|
||||
}
|
||||
```
|
||||
|
||||
You'll notice that when you try to remove an item `ReactTransitionGroup` keeps it in the DOM. If you're using an unminified build of React with add-ons you'll see a warning that React was expecting an animation or transition to occur. That's because `ReactTransitionGroup` keeps your DOM elements on the page until the animation completes. Try adding this CSS:
|
||||
You'll notice that when you try to remove an item `ReactCSSTransitionGroup` keeps it in the DOM. If you're using an unminified build of React with add-ons you'll see a warning that React was expecting an animation or transition to occur. That's because `ReactCSSTransitionGroup` keeps your DOM elements on the page until the animation completes. Try adding this CSS:
|
||||
|
||||
```css
|
||||
.example-leave {
|
||||
@@ -80,18 +84,36 @@ You'll notice that when you try to remove an item `ReactTransitionGroup` keeps i
|
||||
}
|
||||
```
|
||||
|
||||
## Disabling Animations
|
||||
### Disabling Animations
|
||||
|
||||
You can disable animating `enter` or `leave` animations if you want. For example, sometimes you may want an `enter` animation and no `leave` animation, but `ReactTransitionGroup` waits for an animation to complete before removing your DOM node. You can add `transitionEnter={false}` or `transitionLeave={false}` props to `ReactTransitionGroup` to disable these animations.
|
||||
You can disable animating `enter` or `leave` animations if you want. For example, sometimes you may want an `enter` animation and no `leave` animation, but `ReactCSSTransitionGroup` waits for an animation to complete before removing your DOM node. You can add `transitionEnter={false}` or `transitionLeave={false}` props to `ReactCSSTransitionGroup` to disable these animations.
|
||||
|
||||
## Rendering a Different Component
|
||||
## Low-level API: `ReactTransitionGroup`
|
||||
|
||||
`ReactTransitionGroup` is the basis for animations. When children are declaratively added or removed from it (as in the example above) special lifecycle hooks are called on them.
|
||||
|
||||
### `componentWillEnter(callback)`
|
||||
|
||||
This is called at the same time as `componentDidMount()` for components added to an existing `TransitionGroup`. It will block other animations from occurring until `callback` is called. It will not be called on the initial render of a `TransitionGroup`.
|
||||
|
||||
### `componentDidEnter()`
|
||||
|
||||
This is called after the `callback` function that was passed to `componentWillEnter` is called.
|
||||
|
||||
### `componentWillLeave(callback)`
|
||||
|
||||
This is called when the child has been removed from the `ReactTransitionGroup`. Though the child has been removed, `ReactTransitionGroup` will keep it in the DOM until `callback` is called.
|
||||
|
||||
### `componentDidLeave()`
|
||||
|
||||
This is called when the `willLeave` `callback` is called (at the same time as `componentWillUnmount`).
|
||||
|
||||
### Rendering a Different Component
|
||||
|
||||
By default `ReactTransitionGroup` renders as a `span`. You can change this behavior by providing a `component` prop. For example, here's how you would render a `<ul>`:
|
||||
|
||||
```javascript{3}
|
||||
<ReactTransitionGroup
|
||||
transitionName="example"
|
||||
component={React.DOM.ul}>
|
||||
```javascript{1}
|
||||
<ReactTransitionGroup component={React.DOM.ul}>
|
||||
...
|
||||
</ReactTransitionGroup>
|
||||
```
|
||||
|
||||
@@ -17,7 +17,7 @@ In React, data flows one way: from owner to child. This is because data only flo
|
||||
|
||||
However, there are lots of applications that require you to read some data and flow it back into your program. For example, when developing forms, you'll often want to update some React `state` when you receive user input. Or perhaps you want to perform layout in JavaScript and react to changes in some DOM element size.
|
||||
|
||||
In React, you would implement this by listening to a "change" event, read from your data source (usually the DOM) and call `setState()` on one of your components. "Closing the data flow loop" explicitly leads to more understandable and easier-to-maintain programs. See [our forms documentation](./forms.html) for more information.
|
||||
In React, you would implement this by listening to a "change" event, read from your data source (usually the DOM) and call `setState()` on one of your components. "Closing the data flow loop" explicitly leads to more understandable and easier-to-maintain programs. See [our forms documentation](/react/docs/forms.html) for more information.
|
||||
|
||||
Two-way binding -- implicitly enforcing that some value in the DOM is always consistent with some React `state` -- is concise and supports a wide variety of applications. We've provided `ReactLink`: syntactic sugar for setting up the common data flow loop pattern described above, or "linking" some data source to React `state`.
|
||||
|
||||
@@ -62,10 +62,12 @@ var WithLink = React.createClass({
|
||||
});
|
||||
```
|
||||
|
||||
`LinkedStateMixin` adds a method ot your React component called `linkState()`. `linkState()` returns a `ReactLink` object which contains the current value of the React state and a callback to change it.
|
||||
`LinkedStateMixin` adds a method to your React component called `linkState()`. `linkState()` returns a `ReactLink` object which contains the current value of the React state and a callback to change it.
|
||||
|
||||
`ReactLink` objects can be passed up and down the tree as props, so it's easy (and explicit) to set up two-way binding between a component deep in the hierarchy and state that lives higher in the hierarchy.
|
||||
|
||||
Note that `<input>` supports ReactLink for both `value` and `checked`.
|
||||
|
||||
## Under the Hood
|
||||
|
||||
There are two sides to `ReactLink`: the place where you create the `ReactLink` instance and the place where you use it. To prove how simple `ReactLink` is, let's rewrite each side separately to be more explicit.
|
||||
|
||||
@@ -4,7 +4,7 @@ title: Class Name Manipulation
|
||||
layout: docs
|
||||
permalink: class-name-manipulation.html
|
||||
prev: two-way-binding-helpers.html
|
||||
next: examples.html
|
||||
next: test-utils.html
|
||||
---
|
||||
|
||||
`classSet()` is a neat utility for easily manipulating the DOM `class` string.
|
||||
|
||||
141
docs/docs/09.4-test-utils.md
Normal file
141
docs/docs/09.4-test-utils.md
Normal file
@@ -0,0 +1,141 @@
|
||||
---
|
||||
id: test-utils
|
||||
title: Test Utilities
|
||||
layout: docs
|
||||
permalink: test-utils.html
|
||||
prev: class-name-manipulation.html
|
||||
next: clone-with-props.html
|
||||
---
|
||||
|
||||
`React.addons.TestUtils` makes it easy to test React components in the testing framework of your choice (we use [Jasmine](http://pivotal.github.io/jasmine/) with [jsdom](https://github.com/tmpvar/jsdom)).
|
||||
|
||||
### Simulate
|
||||
|
||||
```javascript
|
||||
Simulate.{eventName}(DOMElement element, object eventData)
|
||||
```
|
||||
|
||||
Simulate an event dispatch on a DOM node with optional `eventData` event data. **This is possibly the single most useful utility in `ReactTestUtils`.**
|
||||
|
||||
Example usage:
|
||||
|
||||
```javascript
|
||||
var node = this.refs.input.getDOMNode();
|
||||
React.addons.TestUtils.Simulate.click(node);
|
||||
React.addons.TestUtils.Simulate.change(node);
|
||||
React.addons.TestUtils.Simulate.keyDown(node, {key: "Enter"});
|
||||
```
|
||||
|
||||
`Simulate` has a method for every event that React understands.
|
||||
|
||||
### renderIntoDocument
|
||||
|
||||
```javascript
|
||||
ReactComponent renderIntoDocument(ReactComponent instance)
|
||||
```
|
||||
|
||||
Render a component into a detached DOM node in the document. **This function requires a DOM.**
|
||||
|
||||
### mockComponent
|
||||
|
||||
```javascript
|
||||
object mockComponent(function componentClass, string? tagName)
|
||||
```
|
||||
|
||||
Pass a mocked component module to this method to augment it with useful methods that allow it to be used as a dummy React component. Instead of rendering as usual, the component will become a simple `<div>` (or other tag if `mockTagName` is provided) containing any provided children.
|
||||
|
||||
### isComponentOfType
|
||||
|
||||
```javascript
|
||||
boolean isComponentOfType(ReactComponent instance, function componentClass)
|
||||
```
|
||||
|
||||
Returns true if `instance` is an instance of a React `componentClass`.
|
||||
|
||||
### isDOMComponent
|
||||
|
||||
```javascript
|
||||
boolean isDOMComponent(ReactComponent instance)
|
||||
```
|
||||
|
||||
Returns true if `instance` is a DOM component (such as a `<div>` or `<span>`).
|
||||
|
||||
### isCompositeComponent
|
||||
|
||||
```javascript
|
||||
boolean isCompositeComponent(ReactComponent instance)`
|
||||
```
|
||||
|
||||
Returns true if `instance` is a composite component (created with `React.createClass()`)
|
||||
|
||||
### isCompositeComponentWithType
|
||||
|
||||
```javascript
|
||||
boolean isCompositeComponentWithType(ReactComponent instance, function componentClass)
|
||||
```
|
||||
|
||||
The combination of `isComponentOfType()` and `isCompositeComponent()`.
|
||||
|
||||
### isTextComponent
|
||||
|
||||
```javascript
|
||||
boolean isTextComponent(ReactComponent instance)
|
||||
```
|
||||
|
||||
Returns true if `instance` is a plain text component.
|
||||
|
||||
### findAllInRenderedTree
|
||||
|
||||
```javascript
|
||||
array findAllInRenderedTree(ReactComponent tree, function test)
|
||||
```
|
||||
|
||||
Traverse all components in `tree` and accumulate all components where `test(component)` is true. This is not that useful on its own, but it's used as a primitive for other test utils.
|
||||
|
||||
### scryRenderedDOMComponentsWithClass
|
||||
|
||||
```javascript
|
||||
array scryRenderedDOMComponentsWithClass(ReactComponent tree, string className)
|
||||
```
|
||||
|
||||
Finds all instance of components in the rendered tree that are DOM components with the class name matching `className`.
|
||||
|
||||
### findRenderedDOMComponentWithClass
|
||||
|
||||
```javascript
|
||||
ReactComponent findRenderedDOMComponentWithClass(ReactComponent tree, string className)
|
||||
```
|
||||
|
||||
Like `scryRenderedDOMComponentsWithClass()` but expects there to be one result, and returns that one result, or throws exception if there is any other number of matches besides one.
|
||||
|
||||
### scryRenderedDOMComponentsWithTag
|
||||
|
||||
```javascript
|
||||
array scryRenderedDOMComponentsWithTag(ReactComponent tree, string tagName)
|
||||
```
|
||||
|
||||
Finds all instance of components in the rendered tree that are DOM components with the tag name matching `tagName`.
|
||||
|
||||
### findRenderedDOMComponentWithTag
|
||||
|
||||
```javascript
|
||||
ReactComponent findRenderedDOMComponentWithTag(ReactComponent tree, string tagName)
|
||||
```
|
||||
|
||||
Like `scryRenderedDOMComponentsWithTag()` but expects there to be one result, and returns that one result, or throws exception if there is any other number of matches besides one.
|
||||
|
||||
### scryRenderedComponentsWithType
|
||||
|
||||
```javascript
|
||||
array scryRenderedComponentsWithType(ReactComponent tree, function componentClass)
|
||||
```
|
||||
|
||||
Finds all instances of components with type equal to `componentClass`.
|
||||
|
||||
### findRenderedComponentWithType
|
||||
|
||||
```javascript
|
||||
ReactComponent findRenderedComponentWithType(ReactComponent tree, function componentClass)
|
||||
```
|
||||
|
||||
Same as `scryRenderedComponentsWithType()` but expects there to be one result and returns that one result, or throws exception if there is any other number of matches besides one.
|
||||
14
docs/docs/09.5-clone-with-props.md
Normal file
14
docs/docs/09.5-clone-with-props.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
id: clone-with-props
|
||||
title: Cloning Components
|
||||
layout: docs
|
||||
permalink: clone-with-props.html
|
||||
prev: test-utils.html
|
||||
next: update.html
|
||||
---
|
||||
|
||||
In rare situations a component may want to change the props of a component that it doesn't own (like changing the `className` of a component passed as `this.props.children`). Other times it may want to make multiple copies of a component passed to it. `cloneWithProps()` makes this possible.
|
||||
|
||||
#### `ReactComponent React.addons.cloneWithProps(ReactComponent component, object? extraProps)`
|
||||
|
||||
Do a shallow copy of `component` and merge any props provided by `extraProps`. Props are merged in the same manner as [`transferPropsTo()`](/react/docs/component-api.html#transferpropsto), so props like `className` will be merged intelligently.
|
||||
62
docs/docs/09.6-update.md
Normal file
62
docs/docs/09.6-update.md
Normal file
@@ -0,0 +1,62 @@
|
||||
---
|
||||
id: update
|
||||
title: Immutability Helpers
|
||||
layout: docs
|
||||
permalink: update.html
|
||||
prev: clone-with-props.html
|
||||
---
|
||||
|
||||
React lets you use whatever style of data management you want, including mutation. However, if you can use immutable data in performance-critical parts of your application it's easy to implement a fast `shouldComponentUpdate()` method to significantly speed up your app.
|
||||
|
||||
Dealing with immutable data in JavaScript is more difficult than in languages designed for it, like [Clojure](http://clojure.org/). However, we've provided a simple immutability helper, `update()`, that makes dealing with this type of data much easier, *without* fundamentally changing how your data is represented.
|
||||
|
||||
## The main idea
|
||||
|
||||
If you mutate data like this:
|
||||
|
||||
```javascript
|
||||
myData.x.y.z = 7;
|
||||
myData.a.b.push(9);
|
||||
```
|
||||
|
||||
you have no way of determining which data has changed since the previous copy is destroyed. Instead, you need to create a new copy of `myData` and change only the parts of it that need to be changed. Then you can compare the old copy of `myData` with the new one in `shouldComponentUpdate()` using triple-equals:
|
||||
|
||||
```javascript
|
||||
var newData = deepCopy(myData);
|
||||
newData.x.y.z = 7;
|
||||
newData.a.b.push(9);
|
||||
```
|
||||
|
||||
Unfortunately, deep copies are expensive, and sometimes impossible. You can alleviate this by only copying objects that need to be changed and by reusing the objects that haven't changed. Unfortunately, in today's JavaScript this can be cumbersome:
|
||||
|
||||
```javascript
|
||||
var newData = extend(myData, {
|
||||
x: extend(myData.x, {
|
||||
y: extend(myData.x.y, {z: 7}),
|
||||
}),
|
||||
a: extend(myData.a, {b: myData.a.b.concat(9)})
|
||||
});
|
||||
```
|
||||
|
||||
While this is fairly performant (since it only shallow copies `log n` objects and reuses the rest), it's a big pain to write. Look at all the repetition! This is not only annoying, but also provides a large surface area for bugs.
|
||||
|
||||
`update()` provides simple syntactic sugar around this pattern to make writing this code easier. This code becomes:
|
||||
|
||||
```javascript
|
||||
var newData = React.addons.update(myData, {
|
||||
x: {y: {z: {$set: 7}}},
|
||||
a: {b: {$push: [7]}}
|
||||
});
|
||||
```
|
||||
|
||||
While the syntax takes a little getting used to (though it's inspired by [MongoDB's query language](http://docs.mongodb.org/manual/core/crud-introduction/#query)) there's no redundancy, it's statically analyzable and it's not much more typing than the mutative version.
|
||||
|
||||
The `$`-prefixed keys are called *directives*. The data structure they are "mutating" is called the *target*.
|
||||
|
||||
## Available directives
|
||||
|
||||
* `{$push: array}` `push()` all the items in `array` on the target
|
||||
* `{$unshift: array}` `unshift()` all the items in `array` on the target
|
||||
* `{$splice: array of arrays}` for each item in `array()` call `splice()` on the target with the parameters provided by the item.
|
||||
* `{$set: any}` replace the target entirely
|
||||
* `{$merge: object}` merge the keys of `object` with the target
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
id: examples
|
||||
title: Examples
|
||||
layout: docs
|
||||
permalink: examples.html
|
||||
prev: addons.html
|
||||
---
|
||||
|
||||
### Production Apps
|
||||
|
||||
* All of [Instagram.com](http://instagram.com/) is built on React.
|
||||
* Many components on [Facebook.com](http://www.facebook.com/), including the commenting interface, ads creation flows, and page insights.
|
||||
* [Khan Academy](http://khanacademy.org/) is using React for most new JS development.
|
||||
|
||||
|
||||
### Sample Code
|
||||
|
||||
* We've included [a step-by-step comment box tutorial](./tutorial.html).
|
||||
* [The React starter kit](/react/downloads.html) includes several examples which you can [view online in our GitHub repository](https://github.com/facebook/react/tree/master/examples/).
|
||||
* [React Page](https://github.com/facebook/react-page) is a simple React project creator to get you up-and-running quickly with React. It supports both server-side and client-side rendering, source transform and packaging JSX files using CommonJS modules, and instant reload.
|
||||
* [React one-hour email](https://github.com/petehunt/react-one-hour-email/commits/master) goes step-by-step from a static HTML mock to an interactive email reader (written in just one hour!)
|
||||
* [Rendr + React app template](https://github.com/petehunt/rendr-react-template/) demonstrates how to use React's server rendering capabilities.
|
||||
10
docs/docs/complementary-tools.md
Normal file
10
docs/docs/complementary-tools.md
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
id: complementary-tools
|
||||
title: Complementary Tools
|
||||
layout: docs
|
||||
permalink: complementary-tools.html
|
||||
prev: videos.html
|
||||
next: examples.html
|
||||
---
|
||||
|
||||
This page has moved to the [GitHub wiki](https://github.com/facebook/react/wiki/Complementary-Tools).
|
||||
28
docs/docs/examples.md
Normal file
28
docs/docs/examples.md
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
id: examples
|
||||
title: Examples
|
||||
layout: docs
|
||||
permalink: examples.html
|
||||
prev: complementary-tools.html
|
||||
---
|
||||
|
||||
### Production Apps
|
||||
|
||||
* **[Instagram.com](http://instagram.com/)** is 100% built on React, both public site and internal tools.
|
||||
* **[Facebook.com](http://www.facebook.com/)**'s commenting interface, business management tools, [Lookback video editor](http://facebook.com/lookback/edit), page insights, and most, if not all, new JS development.
|
||||
* **[Khan Academy](http://khanacademy.org/)** uses React for most new JS development.
|
||||
* **[Sberbank](http://sberbank.ru/moscow/ru/person/)**, Russia's number one bank, is built with React.
|
||||
* **[The New York Times's 2014 Red Carpet Project](http://www.nytimes.com/interactive/2014/02/02/fashion/red-carpet-project.html?_r=0)** is built with React.
|
||||
|
||||
### Sample Code
|
||||
|
||||
* **[React starter kit](/react/downloads.html)** Includes several examples which you can [view online in our GitHub repository](https://github.com/facebook/react/tree/master/examples/).
|
||||
* **[React one-hour email](https://github.com/petehunt/react-one-hour-email/commits/master)** Goes step-by-step from a static HTML mock to an interactive email reader, written in just one hour!
|
||||
* **[React server rendering example](https://github.com/mhart/react-server-example)** Demonstrates how to use React's server rendering capabilities.
|
||||
|
||||
### Open-Source Demos
|
||||
|
||||
* **[TodoMVC](https://github.com/tastejs/todomvc/tree/gh-pages/architecture-examples/react/js)**
|
||||
* **[Khan Academy question editor](https://github.com/khan/perseus)** (Browse their GitHub account for many more production apps!)
|
||||
* **[github-issue-viewer](https://github.com/jaredly/github-issues-viewer)**
|
||||
* **[hn-react](https://github.com/prabirshrestha/hn-react)** Dead-simple Hacker News client.
|
||||
97
docs/docs/flux-overview.md
Normal file
97
docs/docs/flux-overview.md
Normal file
@@ -0,0 +1,97 @@
|
||||
---
|
||||
id: flux-overview
|
||||
title: Flux Application Architecture
|
||||
layout: docs
|
||||
next: flux-todo-list.html
|
||||
---
|
||||
|
||||
Flux is the application architecture that Facebook uses for building client-side web applications. It complements React's composable view components by utilizing a unidirectional data flow. It's more of a pattern rather than a formal framework, and you can start using Flux immediately without a lot of new code.
|
||||
|
||||
<figure><iframe width="560" height="315" src="//www.youtube.com/embed/nYkdrAPrdcw?list=PLb0IAmt7-GS188xDYE-u1ShQmFFGbrk0v" frameborder="0" allowfullscreen></iframe></figure>
|
||||
|
||||
Flux applications have three major parts: the dispatcher, the stores, and the views (React components). These should not be confused with Model-View-Controller. Controllers do exist in a Flux application, but they are controller-views — views often found at the top of the hierarchy that retrieve data from the stores and pass this data down to their children. Additionally, actions — dispatcher helper methods — are often used to support a semantic dispatcher API. It can be useful to think of them as a fourth part of the Flux update cycle.
|
||||
|
||||
Flux eschews MVC in favor of a unidirectional data flow. When a user interacts with a React view, the view propagates an action through a central dispatcher, to the various stores that hold the application's data and business logic, which updates all of the views that are affected. This works especially well with React's declarative programming style, which allows the store to send updates without specifying how to transition views between states.
|
||||
|
||||
We originally set out to deal correctly with derived data: for example, we wanted to show an unread count for message threads while another view showed a list of threads, with the unread ones highlighted. This was difficult to handle with MVC — marking a single thread as read would update the thread model, and then also need to update the unread count model. These dependencies and cascading updates often occur in a large MVC application, leading to a tangled weave of data flow and unpredictable results.
|
||||
|
||||
Control is inverted with stores: the stores accept updates and reconcile them as appropriate, rather than depending on something external to update its data in a consistent way. Nothing outside the store has any insight into how it manages the data for its domain, helping to keep a clear separation of concerns. This also makes stores more testable than models, especially since stores have no direct setter methods like `setAsRead()`, but instead have only an input point for the payload, which is delivered through the dispatcher and originates with actions.
|
||||
|
||||
|
||||
## Structure and Data Flow
|
||||
|
||||
Data in a Flux application flows in a single direction, in a cycle:
|
||||
|
||||
<pre>
|
||||
Views ---> (actions) ----> Dispatcher ---> (registered callback) ---> Stores -------+
|
||||
Ʌ |
|
||||
| V
|
||||
+-- (Controller-Views "change" event handlers) ---- (Stores emit "change" events) --+
|
||||
</pre>
|
||||
|
||||
A unidirectional data flow is central to the Flux pattern, and in fact Flux takes its name from the Latin word for flow. In the above diagram, the dispatcher, stores and views are independent nodes with distinct inputs and outputs. The actions are simply discrete, semantic helper functions that facilitate passing data to the dispatcher.
|
||||
|
||||
All data flows through the dispatcher as a central hub. Actions most often originate from user interactions with the views, and are nothing more than a call into the dispatcher. The dispatcher then invokes the callbacks that the stores have registered with it, effectively dispatching the data payload contained in the actions to all stores. Within their registered callbacks, stores determine which actions they are interested in, and respond accordingly. The stores then emit a "change" event to alert the controller-views that a change to the data layer has occurred. Controller-views listen for these events and retrieve data from the stores in an event handler. The controller-views call their own `render()` method via `setState()` or `forceUpdate()`, updating themselves and all of their children.
|
||||
|
||||
This structure allows us to reason easily about our application in a way that is reminiscent of functional reactive programming, or more specifically data-flow programming or flow-based programming, where data flows through the application in a single direction — there are no two-way bindings. Application state is maintained only in the stores, allowing the different parts of the application to remain highly decoupled. Where dependencies do occur between stores, they are kept in a strict hierarchy, with synchronous updates managed by the dispatcher.
|
||||
|
||||
We found that two-way data bindings led to cascading updates, where changing one object led to another object changing, which could also trigger more updates. As applications grew, these cascading updates made it very difficult to predict what would change as the result of one user interaction. When updates can only change data within a single round, the system as a whole becomes more predictable.
|
||||
|
||||
Let's look at the various parts of the Flux update cycle up close. A good place to start is the dispatcher.
|
||||
|
||||
|
||||
### A Single Dispatcher
|
||||
|
||||
The dispatcher is the central hub that manages all data flow in a Flux application. It is essentially a registry of callbacks into the stores. Each store registers itself and provides a callback. When the dispatcher responds to an action, all stores in the application are sent the data payload provided by the action via the callbacks in the registry.
|
||||
|
||||
As an application grows, the dispatcher becomes more vital, as it can manage dependencies between stores by invoking the registered callbacks in a specific order. Stores can declaratively wait for other stores to finish updating, and then update themselves accordingly.
|
||||
|
||||
|
||||
### Stores
|
||||
|
||||
Stores contain the application state and logic. Their role is somewhat similar to a model in a traditional MVC, but they manage the state of many objects — they are not instances of one object. Nor are they the same as Backbone's collections. More than simply managing a collection of ORM-style objects, stores manage the application state for a particular __domain__ within the application.
|
||||
|
||||
For example, Facebook's [Lookback Video Editor](https://facebook.com/lookback/edit) utilized a TimeStore that kept track of the playback time position and the playback state. On the other hand, the same application's ImageStore kept track of a collection of images. The TodoStore in our [TodoMVC example](https://github.com/facebook/react/tree/master/examples/todomvc-flux) is similar in that it manages a collection of to-do items. A store exhibits characteristics of both a collection of models and a singleton model of a logical domain.
|
||||
|
||||
As mentioned above, a store registers itself with the dispatcher and provides it with a callback. This callback receives the action's data payload as a parameter. The payload contains a type attribute, identifying the action's type. Within the store's registered callback, a switch statement based on the action's type is used to interpret the payload and to provide the proper hooks into the store's internal methods. This allows an action to result in an update to the state of the store, via the dispatcher. After the stores are updated, they broadcast an event declaring that their state has changed, so the views may query the new state and update themselves.
|
||||
|
||||
|
||||
### Views and Controller-Views
|
||||
|
||||
React provides the kind of composable views we need for the view layer. Close to the top of the nested view hierarchy, a special kind of view listens for events that are broadcast by the stores that it depends on. One could call this a controller-view, as it provides the glue code to get the data from the stores and to pass this data down the chain of its descendants. We might have one of these controller-views governing any significant section of the page.
|
||||
|
||||
When it receives the event from the store, it first requests the new data it needs via the stores' public getter methods. It then calls its own `setState()` or `forceUpdate()` methods, causing its `render()` method and the `render()` method of all its descendants to run.
|
||||
|
||||
We often pass the entire state of the store down the chain of views in a single object, allowing different descendants to use what they need. In addition to keeping the controller-like behavior at the top of the hierarchy, and thus keeping our descendant views as functionally pure as possible, passing down the entire state of the store in a single object also has the effect of reducing the number of props we need to manage.
|
||||
|
||||
Occasionally we may need to add additional controller-views deeper in the hierarchy to keep components simple. This might help us to better encapsulate a section of the hierarchy related to a specific data domain. Be aware, however, that controller-views deeper in the hierarchy can violate the singular flow of data by introducing a new, potentially conflicting entry point for the data flow. In making the decision of whether to add a deep controller-view, balance the gain of simpler components against the complexity of multiple data updates flowing into the hierarchy at different points. These multiple data updates can lead to odd effects, with React's render method getting invoked repeatedly by updates from different controller-views, potentially increasing the difficulty of debugging.
|
||||
|
||||
|
||||
### Actions
|
||||
|
||||
The dispatcher exposes a method that allows a view to trigger a dispatch to the stores, and to include a payload of data, or an action. The action construction may be wrapped into a semantic helper method which sends the payload to the dispatcher. For example, we may want to change the text of a to-do item in a to-do list application. We would create an action with a function signature like `updateText(todoId, newText)` in our `TodoActions` module. This method may be invoked from within our views' event handlers, so we can call it in response to a user action. This action method also adds the action type to the payload, so that when the payload is interpreted in the store, it can respond appropriately to a payload with a particular action type. In our example, this type might be named something like `TODO_UPDATE_TEXT`.
|
||||
|
||||
Actions may also come from other places, such as the server. This happens, for example, during data initialization. It may also happen when the server returns an error code or when the server has updates to provide to the application. We'll talk more about server actions in a future article. In this post we're only concerned with the basics of the data flow.
|
||||
|
||||
|
||||
### What About that Dispatcher?
|
||||
|
||||
As mentioned earlier, the dispatcher is also able to manage dependencies between stores. This functionality is available through the `waitFor()` method within the Dispatcher class. We did not need to use this method within the extremely simple [TodoMVC application](https://github.com/facebook/react/tree/master/examples/todomvc-flux), but we have included it [in the example dispatcher](https://github.com/facebook/react/blob/master/examples/todomvc-flux/js/dispatcher/Dispatcher.js#L110) as an example of what a dispatcher should be able to do in a larger, more complex application.
|
||||
|
||||
Within the TodoStore's registered callback we could explicitly wait for any dependencies to first update before moving forward:
|
||||
|
||||
```javascript
|
||||
case 'TODO_CREATE':
|
||||
Dispatcher.waitFor([
|
||||
PrependedTextStore.dispatcherIndex,
|
||||
YetAnotherStore.dispatcherIndex
|
||||
], function() {
|
||||
TodoStore.create(PrependedTextStore.getText() + ' ' + action.text);
|
||||
TodoStore.emit('change');
|
||||
});
|
||||
break;
|
||||
```
|
||||
|
||||
The arguments for `waitFor()` are an array of dipatcher registry indexes, and a final callback to invoke after the callbacks at the given indexes have completed. Thus the store that is invoking `waitFor()` can depend on the state of another store to inform how it should update its own state.
|
||||
|
||||
A problem arises if we create circular dependencies. If Store A waits for Store B, and B waits for A, then we'll have a very bad situation on our hands. We'll need a more robust dispatcher that flags these circular dependencies with console errors, and this is not easily accomplished with promises. Unfortunately, that's a bit beyond the scope of this documentation. In the future we hope to cover how to build a more robust dispatcher and how to initialize, update, and save the state of the application with persistent data, like a web service API.
|
||||
608
docs/docs/flux-todo-list.md
Normal file
608
docs/docs/flux-todo-list.md
Normal file
@@ -0,0 +1,608 @@
|
||||
---
|
||||
id: flux-todo-list
|
||||
title: Flux TodoMVC Tutorial
|
||||
layout: docs
|
||||
prev: flux-overview.html
|
||||
---
|
||||
|
||||
To demonstrate the Flux architecture with some example code, let's take on the classic TodoMVC application. The entire application is available in the React GitHub repo within the [todomvc-flux](https://github.com/facebook/react/tree/master/examples/todomvc-flux) example directory, but let's walk through the development of it a step at a time.
|
||||
|
||||
To begin, we'll need some boilerplate and get up and running with a module system. Node's module system, based on CommonJS, will fit the bill very nicely and we can build off of [react-boilerplate](https://github.com/petehunt/react-boilerplate) to get up and running quickly. Assuming you have npm installed, simply clone the react-boilerplate code from GitHub, and navigate into the resulting directory in Terminal (or whatever CLI application you like). Next run the npm scripts to get up and running: `npm install`, then `npm run build`, and lastly `npm start` to continuously build using Browserify.
|
||||
|
||||
The TodoMVC example has all this built into it as well, but if you're starting with react-boilerplate make sure you edit your package.json file to match the file structure and dependencies described in the TodoMVC example's [package.json](https://github.com/facebook/react/tree/master/examples/todomvc-flux/package.json), or else your code won't match up with the explanations below.
|
||||
|
||||
|
||||
Source Code Structure
|
||||
---------------------
|
||||
The resulting index.js file may be used as the entry point into our app, but we'll put most of our code in a 'js' directory. Let's let Browserify do its thing, and now we'll open a new tab in Terminal (or a GUI file browser) to look at the directory. It should look something like this:
|
||||
|
||||
```
|
||||
myapp
|
||||
|
|
||||
+ ...
|
||||
+ js
|
||||
|
|
||||
+ app.js
|
||||
+ bundle.js // generated by Browserify whenever we make changes.
|
||||
+ index.html
|
||||
+ ...
|
||||
```
|
||||
|
||||
Next we'll dive into the js directory, and layout our application's primary directory structure:
|
||||
|
||||
```
|
||||
myapp
|
||||
|
|
||||
+ ...
|
||||
+ js
|
||||
|
|
||||
+ actions
|
||||
+ components // all React components, both views and controller-views
|
||||
+ constants
|
||||
+ dispatcher
|
||||
+ stores
|
||||
+ app.js
|
||||
+ bundle.js
|
||||
+ index.html
|
||||
+ ...
|
||||
```
|
||||
|
||||
Creating a Dispatcher
|
||||
---------------------
|
||||
|
||||
Now we are ready to create a dispatcher. Here is an naive example of a Dispatcher class, written with JavaScript promises, polyfilled with Jake Archibald's [ES6-Promises](https://github.com/jakearchibald/ES6-Promises) module.
|
||||
|
||||
```javascript
|
||||
var Promise = require('es6-promise').Promise;
|
||||
var merge = require('react/lib/merge');
|
||||
|
||||
var _callbacks = [];
|
||||
var _promises = [];
|
||||
|
||||
/**
|
||||
* Add a promise to the queue of callback invocation promises.
|
||||
* @param {function} callback The Store's registered callback.
|
||||
* @param {object} payload The data from the Action.
|
||||
*/
|
||||
var _addPromise = function(callback, payload) {
|
||||
_promises.push(new Promise(function(resolve, reject) {
|
||||
if (callback(payload)) {
|
||||
resolve(payload);
|
||||
} else {
|
||||
reject(new Error('Dispatcher callback unsuccessful'));
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Empty the queue of callback invocation promises.
|
||||
*/
|
||||
var _clearPromises = function() {
|
||||
_promises = [];
|
||||
};
|
||||
|
||||
var Dispatcher = function() {};
|
||||
Dispatcher.prototype = merge(Dispatcher.prototype, {
|
||||
|
||||
/**
|
||||
* Register a Store's callback so that it may be invoked by an action.
|
||||
* @param {function} callback The callback to be registered.
|
||||
* @return {number} The index of the callback within the _callbacks array.
|
||||
*/
|
||||
register: function(callback) {
|
||||
_callbacks.push(callback);
|
||||
return _callbacks.length - 1; // index
|
||||
},
|
||||
|
||||
/**
|
||||
* dispatch
|
||||
* @param {object} payload The data from the action.
|
||||
*/
|
||||
dispatch: function(payload) {
|
||||
_callbacks.forEach(function(callback) {
|
||||
_addPromise(callback, payload);
|
||||
});
|
||||
Promise.all(_promises).then(_clearPromises);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = Dispatcher;
|
||||
```
|
||||
|
||||
The public API of this basic Dispatcher consists of only two methods: register() and dispatch(). We'll use register() within our stores to register each store's callback. We'll use dispatch() within our actions to trigger the invocation of the callbacks.
|
||||
|
||||
Now we are all set to create a dispatcher that is more specific to our app, which we'll call AppDispatcher.
|
||||
|
||||
```javascript
|
||||
var Dispatcher = require('./Dispatcher');
|
||||
|
||||
var merge = require('react/lib/merge');
|
||||
|
||||
var AppDispatcher = merge(Dispatcher.prototype, {
|
||||
|
||||
/**
|
||||
* A bridge function between the views and the dispatcher, marking the action
|
||||
* as a view action. Another variant here could be handleServerAction.
|
||||
* @param {object} action The data coming from the view.
|
||||
*/
|
||||
handleViewAction: function(action) {
|
||||
this.dispatch({
|
||||
source: 'VIEW_ACTION',
|
||||
action: action
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = AppDispatcher;
|
||||
```
|
||||
|
||||
Now we've created an implementation that is a bit more specific to our needs, with a helper function we can use in the actions coming from our views' event handlers. We might expand on this later to provide a separate helper for server updates, but for now this is all we need.
|
||||
|
||||
|
||||
Creating Stores
|
||||
----------------
|
||||
|
||||
We can use Node's EventEmitter to get started with a store. We need EventEmitter to broadcast the 'change' event to our controller-views. So let's take a look at what that looks like. I've omitted some of the code for the sake of brevity, but for the full version see [TodoStore.js](https://github.com/Facebook/react/blob/master/examples/todomvc-flux/js/stores/TodoStore.js) in the TodoMVC example code.
|
||||
|
||||
```javascript
|
||||
var AppDispatcher = require('../dispatcher/AppDispatcher');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var TodoConstants = require('../constants/TodoConstants');
|
||||
var merge = require('react/lib/merge');
|
||||
|
||||
var CHANGE_EVENT = 'change';
|
||||
|
||||
var _todos = {}; // collection of todo items
|
||||
|
||||
/**
|
||||
* Create a TODO item.
|
||||
* @param {string} text The content of the TODO
|
||||
*/
|
||||
function create(text) {
|
||||
// Using the current timestamp in place of a real id.
|
||||
var id = Date.now();
|
||||
_todos[id] = {
|
||||
id: id,
|
||||
complete: false,
|
||||
text: text
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a TODO item.
|
||||
* @param {string} id
|
||||
*/
|
||||
function destroy(id) {
|
||||
delete _todos[id];
|
||||
}
|
||||
|
||||
var TodoStore = merge(EventEmitter.prototype, {
|
||||
|
||||
/**
|
||||
* Get the entire collection of TODOs.
|
||||
* @return {object}
|
||||
*/
|
||||
getAll: function() {
|
||||
return _todos;
|
||||
},
|
||||
|
||||
emitChange: function() {
|
||||
this.emit(CHANGE_EVENT);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {function} callback
|
||||
*/
|
||||
addChangeListener: function(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {function} callback
|
||||
*/
|
||||
removeChangeListener: function(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
dispatcherIndex: AppDispatcher.register(function(payload) {
|
||||
var action = payload.action;
|
||||
var text;
|
||||
|
||||
switch(action.actionType) {
|
||||
case TodoConstants.TODO_CREATE:
|
||||
text = action.text.trim();
|
||||
if (text !== '') {
|
||||
create(text);
|
||||
TodoStore.emitChange();
|
||||
}
|
||||
break;
|
||||
|
||||
case TodoConstants.TODO_DESTROY:
|
||||
destroy(action.id);
|
||||
TodoStore.emitChange();
|
||||
break;
|
||||
|
||||
// add more cases for other actionTypes, like TODO_UPDATE, etc.
|
||||
}
|
||||
|
||||
return true; // No errors. Needed by promise in Dispatcher.
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
module.exports = TodoStore;
|
||||
```
|
||||
|
||||
There are a few important things to note in the above code. To start, we are maintaining a private data structure called _todos. This object contains all the individual to-do items. Because this variable lives outside the class, but within the closure of the module, it remains private — it cannot be directly changed from the outside. This helps us preserve a distinct input/output interface for the flow of data by making it impossible to update the store without using an action.
|
||||
|
||||
Another important part is the registration of the store's callback with the dispatcher. We pass in our payload handling callback to the dispatcher and preserve the index that this store has in the dispatcher's registry. The callback function currently only handles one actionType, but later we can add as many as we need.
|
||||
|
||||
|
||||
Listening to Changes with a Controller-View
|
||||
-------------------------------------------
|
||||
|
||||
We need a React component near the top of our component hierarchy to listen for changes in the store. In a larger app, we would have more of these listening components, perhaps one for every section of the page. In Facebook's Ads Creation Tool, we have many of these controller-like views, each governing a specific section of the UI. In the Lookback Video Editor, we only had two: one for the animated preview and one for the image selection interface. Here's one for our TodoMVC example. Again, this is slightly abbreviated, but for the full code you can take a look at the TodoMVC example's [TodoApp.react.js](https://github.com/facebook/react/blob/master/examples/todomvc-flux/js/components/TodoApp.react.js)
|
||||
|
||||
```javascript
|
||||
/** @jsx React.DOM */
|
||||
|
||||
var Footer = require('./Footer.react');
|
||||
var Header = require('./Header.react');
|
||||
var MainSection = require('./MainSection.react');
|
||||
var React = require('react');
|
||||
var TodoStore = require('../stores/TodoStore');
|
||||
|
||||
function getTodoState() {
|
||||
return {
|
||||
allTodos: TodoStore.getAll()
|
||||
};
|
||||
}
|
||||
|
||||
var TodoApp = React.createClass({
|
||||
|
||||
getInitialState: function() {
|
||||
return getTodoState();
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
TodoStore.addChangeListener(this._onChange);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
TodoStore.removeChangeListener(this._onChange);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {object}
|
||||
*/
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<Header />
|
||||
<MainSection
|
||||
allTodos={this.state.allTodos}
|
||||
areAllComplete={this.state.areAllComplete}
|
||||
/>
|
||||
<Footer allTodos={this.state.allTodos} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
_onChange: function() {
|
||||
this.setState(getTodoState());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = TodoApp;
|
||||
```
|
||||
|
||||
Now we're in our familiar React territory, utilizing React's lifecycle methods. We set up the initial state of this controller-view in getInitialState(), register an event listener in componentDidMount(), and then clean up after ourselves within componentWillUnmount(). We render a containing div and pass down the collection of states we got from the TodoStore.
|
||||
|
||||
The Header component contains the primary text input for the application, but it does not need to know the state of the store. The MainSection and Footer do need this data, so we pass it down to them.
|
||||
|
||||
More Views
|
||||
----------
|
||||
At a high level, the React component hierarchy of the app looks like this:
|
||||
|
||||
```javascript
|
||||
<TodoApp>
|
||||
<Header>
|
||||
<TodoTextInput />
|
||||
|
||||
<MainSection>
|
||||
<ul>
|
||||
<TodoItem />
|
||||
</ul>
|
||||
</MainSection>
|
||||
|
||||
</TodoApp>
|
||||
```
|
||||
If a TodoItem is in edit mode, it will also render a TodoTextInput as a child. Let's take a look at how some of these components display the data they receive as props, and how they communicate through actions with the dispatcher.
|
||||
The MainSection needs to iterate over the collection of to-do items it received from TodoApp to create the list of TodoItems. In the component's render() method, we can do that iteration like so:
|
||||
|
||||
```javascript
|
||||
var allTodos = this.props.allTodos;
|
||||
|
||||
for (var key in allTodos) {
|
||||
todos.push(<TodoItem key={key} todo={allTodos[key]} />);
|
||||
}
|
||||
|
||||
return (
|
||||
<section id="main">
|
||||
<ul id="todo-list">{todos}</ul>
|
||||
);
|
||||
```
|
||||
Now each TodoItem can display it's own text, and perform actions utilizing it's own ID. Explaining all the different actions that a TodoItem can invoke in the TodoMVC example goes beyond the scope of this article, but let's just take a look at the action that deletes one of the to-do items. Here is an abbreviated version of the TodoItem:
|
||||
|
||||
```javascript
|
||||
/** @jsx React.DOM */
|
||||
|
||||
var React = require('react');
|
||||
var TodoActions = require('../actions/TodoActions');
|
||||
var TodoTextInput = require('./TodoTextInput.react');
|
||||
|
||||
var TodoItem = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
todo: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var todo = this.props.todo;
|
||||
|
||||
return (
|
||||
<li
|
||||
key={todo.id}>
|
||||
<label>
|
||||
{todo.text}
|
||||
</label>
|
||||
<button className="destroy" onClick={this._onDestroyClick} />
|
||||
</li>
|
||||
);
|
||||
},
|
||||
|
||||
_onDestroyClick: function() {
|
||||
TodoActions.destroy(this.props.todo.id);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = TodoItem;
|
||||
```
|
||||
|
||||
With a destroy action available in our library of TodoActions, and a store ready to handle it, connecting the user's interaction with application state changes could not be simpler. We just wrap our onClick handler around the destroy action, provide it with the id, and we're done. Now the user can click the destroy button and kick off the Flux cycle to update the rest of the application.
|
||||
|
||||
Text input, on the other hand, is just a bit more complicated because we need to hang on to the state of the text input within the React component itself. Let's take a look at how TodoTextInput works.
|
||||
|
||||
As you'll see below, with every change to the input, React expects us to update the state of the component. So when we are finally ready to save the text inside the input, we will put the value held in the component's state in the action's payload. This is UI state, rather than application state, and keeping that distinction in mind is a good guide for where state should live. All application state should live in the store, while components occasionally hold on to UI state. Ideally, React components preserve as little state as possible.
|
||||
|
||||
Because TodoTextInput is being used in multiple places within our application, with different behaviors, we'll need to pass the onSave method in as a prop from the component's parent. This allows onSave to invoke different actions depending on where it is used.
|
||||
|
||||
```javascript
|
||||
/** @jsx React.DOM */
|
||||
|
||||
var React = require('react');
|
||||
var ReactPropTypes = React.PropTypes;
|
||||
|
||||
var ENTER_KEY_CODE = 13;
|
||||
|
||||
var TodoTextInput = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
className: ReactPropTypes.string,
|
||||
id: ReactPropTypes.string,
|
||||
placeholder: ReactPropTypes.string,
|
||||
onSave: ReactPropTypes.func.isRequired,
|
||||
value: ReactPropTypes.string
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
value: this.props.value || ''
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {object}
|
||||
*/
|
||||
render: function() /*object*/ {
|
||||
return (
|
||||
<input
|
||||
className={this.props.className}
|
||||
id={this.props.id}
|
||||
placeholder={this.props.placeholder}
|
||||
onBlur={this._save}
|
||||
onChange={this._onChange}
|
||||
onKeyDown={this._onKeyDown}
|
||||
value={this.state.value}
|
||||
autoFocus={true}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Invokes the callback passed in as onSave, allowing this component to be
|
||||
* used in different ways.
|
||||
*/
|
||||
_save: function() {
|
||||
this.props.onSave(this.state.value);
|
||||
this.setState({
|
||||
value: ''
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {object} event
|
||||
*/
|
||||
_onChange: function(/*object*/ event) {
|
||||
this.setState({
|
||||
value: event.target.value
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {object} event
|
||||
*/
|
||||
|
||||
_onKeyDown: function(event) {
|
||||
if (event.keyCode === ENTER_KEY_CODE) {
|
||||
this._save();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = TodoTextInput;
|
||||
```
|
||||
|
||||
The Header passes in the onSave method as a prop to allow the TodoTextInput to create new
|
||||
to-do items:
|
||||
|
||||
```javascript
|
||||
/** @jsx React.DOM */
|
||||
|
||||
var React = require('react');
|
||||
var TodoActions = require('../actions/TodoActions');
|
||||
var TodoTextInput = require('./TodoTextInput.react');
|
||||
|
||||
var Header = React.createClass({
|
||||
|
||||
/**
|
||||
* @return {object}
|
||||
*/
|
||||
render: function() {
|
||||
return (
|
||||
<header id="header">
|
||||
<h1>todos</h1>
|
||||
<TodoTextInput
|
||||
id="new-todo"
|
||||
placeholder="What needs to be done?"
|
||||
onSave={this._onSave}
|
||||
/>
|
||||
</header>
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler called within TodoTextInput.
|
||||
* Defining this here allows TodoTextInput to be used in multiple places
|
||||
* in different ways.
|
||||
* @param {string} text
|
||||
*/
|
||||
_onSave: function(text) {
|
||||
TodoActions.create(text);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = Header;
|
||||
```
|
||||
|
||||
In a different context, such as in editing mode for an existing to-do item, we might pass an onSave callback that invokes `TodoActions.update(text)` instead.
|
||||
|
||||
|
||||
Creating Semantic Actions
|
||||
-------------------------
|
||||
|
||||
Here is the basic code for the two actions we used above in our views:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* TodoActions
|
||||
*/
|
||||
|
||||
var AppDispatcher = require('../dispatcher/AppDispatcher');
|
||||
var TodoConstants = require('../constants/TodoConstants');
|
||||
|
||||
var TodoActions = {
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
*/
|
||||
create: function(text) {
|
||||
AppDispatcher.handleViewAction({
|
||||
actionType: TodoConstants.TODO_CREATE,
|
||||
text: text
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} id
|
||||
*/
|
||||
destroy: function(id) {
|
||||
AppDispatcher.handleViewAction({
|
||||
actionType: TodoConstants.TODO_DESTROY,
|
||||
id: id
|
||||
});
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = TodoActions;
|
||||
```
|
||||
|
||||
As you can see, we really would not need to have the helpers AppDispatcher.handleViewAction() or TodoActions.create(). We could, in theory, call AppDispatcher.dispatch() directly and provide a payload. But as our application grows, having these helpers keeps the code clean and semantic. It's just a lot cleaner to write TodoActions.destroy(id) instead of writing a whole lot of things that our TodoItem shouldn't have to know about.
|
||||
|
||||
The payload produced by the TodoActions.create() will look like:
|
||||
|
||||
```javascript
|
||||
{
|
||||
source: 'VIEW_ACTION',
|
||||
action: {
|
||||
type: 'TODO_CREATE',
|
||||
text: 'Write blog post about Flux'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This payload is provided to the TodoStore through its registered callback. The TodoStore then broadcasts the 'change' event, and the MainSection responds by fetching the new collection of to-do items from the TodoStore and changing its state. This change in state causes the TodoApp component to call its own render() method, and the render() method of all of its descendents.
|
||||
|
||||
Start Me Up
|
||||
-----------
|
||||
|
||||
The bootstrap file of our application is app.js. It simply takes the TodoApp component and renders it in the root element of the application.
|
||||
|
||||
```javascript
|
||||
/** @jsx React.DOM */
|
||||
|
||||
var React = require('react');
|
||||
|
||||
var TodoApp = require('./components/TodoApp.react');
|
||||
|
||||
React.renderComponent(
|
||||
<TodoApp />,
|
||||
document.getElementById('todoapp')
|
||||
);
|
||||
```
|
||||
|
||||
Adding Dependency Management to the Dispatcher
|
||||
----------------------------------------------
|
||||
|
||||
As I said previously, our Dispatcher implementation is a bit naive. It's pretty good, but it will not suffice for most applications. We need a way to be able to manage dependencies between Stores. Let's add that functionality with a waitFor() method within the main body of the Dispatcher class.
|
||||
|
||||
We'll need another public method, waitFor().
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @param {array} promisesIndexes
|
||||
* @param {function} callback
|
||||
*/
|
||||
waitFor: function(promiseIndexes, callback) {
|
||||
var selectedPromises = _promises.filter(function(/*object*/ _, /*number*/ j) {
|
||||
return promiseIndexes.indexOf(j) !== -1;
|
||||
});
|
||||
Promise.all(selectedPromises).then(callback);
|
||||
}
|
||||
```
|
||||
|
||||
Now within the TodoStore callback we can explicitly wait for any dependencies to first update before moving forward. However, if Store A waits for Store B, and B waits for A, then a circular dependency will occur. A more robust dispatcher is required to flag this scenario with warnings in the console.
|
||||
|
||||
The Future of Flux
|
||||
------------------
|
||||
|
||||
A lot of people ask if Facebook will release Flux as an open source framework. Really, Flux is just an architecture, not a framework. But perhaps a Flux boilerplate project might make sense, if there is enough interest. Please let us know if you'd like to see us do this.
|
||||
|
||||
Thanks for taking the time to read about how we build client-side applications at Facebook. We hope Flux proves as useful to you as it has to us.
|
||||
@@ -28,7 +28,7 @@ In the root directory of the starter kit, create a `helloworld.html` with the fo
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="build/react.min.js"></script>
|
||||
<script src="build/react.js"></script>
|
||||
<script src="build/JSXTransformer.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -44,7 +44,7 @@ In the root directory of the starter kit, create a `helloworld.html` with the fo
|
||||
</html>
|
||||
```
|
||||
|
||||
The XML syntax inside of JavaScript is called JSX; check out the [JSX syntax](jsx-in-depth.html) to learn more about it. In order to translate it to vanilla JavaScript we use `<script type="text/jsx">` and include `JSXTransformer.js` to actually perform the transformation in the browser.
|
||||
The XML syntax inside of JavaScript is called JSX; check out the [JSX syntax](/react/docs/jsx-in-depth.html) to learn more about it. In order to translate it to vanilla JavaScript we use `<script type="text/jsx">` and include `JSXTransformer.js` to actually perform the transformation in the browser.
|
||||
|
||||
### Separate File
|
||||
|
||||
@@ -90,7 +90,7 @@ React.renderComponent(
|
||||
|
||||
> Note:
|
||||
>
|
||||
> The comment parser is very strict right now, in order for it to pick up the `@jsx` modifier, two conditions are required. The `@jsx` comment block must be the first comment on the file. The comment must start with `/**` (`/*` and `//` will not work). If the parser can't find the `@jsx` comment, it will output the file without transforming it.
|
||||
> The comment parser is very strict right now; in order for it to pick up the `@jsx` modifier, two conditions are required. The `@jsx` comment block must be the first comment on the file. The comment must start with `/**` (`/*` and `//` will not work). If the parser can't find the `@jsx` comment, it will output the file without transforming it.
|
||||
|
||||
Update your HTML file as below:
|
||||
|
||||
@@ -99,7 +99,7 @@ Update your HTML file as below:
|
||||
<html>
|
||||
<head>
|
||||
<title>Hello React!</title>
|
||||
<script src="build/react.min.js"></script>
|
||||
<script src="build/react.js"></script>
|
||||
<!-- No need for JSXTransformer! -->
|
||||
</head>
|
||||
<body>
|
||||
@@ -115,4 +115,4 @@ If you want to use React within a module system, [fork our repo](http://github.c
|
||||
|
||||
## Next Steps
|
||||
|
||||
Check out [the tutorial](tutorial.html) and the other examples in the `/examples` directory to learn more. Good luck, and welcome!
|
||||
Check out [the tutorial](/react/docs/tutorial.html) and the other examples in the `/examples` directory to learn more. Good luck, and welcome!
|
||||
|
||||
@@ -11,6 +11,35 @@ next: component-api.html
|
||||
`React` is the entry point to the React framework. If you're using one of the prebuilt packages it's available as a global; if you're using CommonJS modules you can `require()` it.
|
||||
|
||||
|
||||
### React.Children
|
||||
|
||||
`React.Children` provides utilities for dealing with the `this.props.children` opaque data structure.
|
||||
|
||||
#### React.Children.map
|
||||
|
||||
```javascript
|
||||
object React.Children.map(object children, function fn [, object context])
|
||||
```
|
||||
|
||||
Invoke `fn` on every immediate child contained within `children` with `this` set to `context`. If `children` is a nested object or array it will be traversed: `fn` will never be passed the container objects. If children is `null` or `undefined` returns `null` or `undefined` rather than an empty object.
|
||||
|
||||
#### React.Children.forEach
|
||||
|
||||
```javascript
|
||||
React.Children.forEach(object children, function fn [, object context])
|
||||
```
|
||||
|
||||
Like `React.Children.map()` but does not return an object.
|
||||
|
||||
#### React.Children.only
|
||||
|
||||
```javascript
|
||||
object React.Children.only(object children)
|
||||
```
|
||||
|
||||
Return the only child in `children`. Throws otherwise.
|
||||
|
||||
|
||||
### React.DOM
|
||||
|
||||
`React.DOM` provides all of the standard HTML tags needed to build a React app. You generally don't use it directly; instead, just include it as part of the `/** @jsx React.DOM */` docblock.
|
||||
@@ -31,9 +60,9 @@ Configure React's event system to handle touch events on mobile devices.
|
||||
function createClass(object specification)
|
||||
```
|
||||
|
||||
Creates a component given a specification. A component implements a `render` method which returns **one single** child. That child may have an arbitrarily deep child structure. One thing that makes components different than standard prototypal classes is that you don't need to call new on them. They are convenience wrappers that construct backing instances (via new) for you.
|
||||
Create a component given a specification. A component implements a `render` method which returns **one single** child. That child may have an arbitrarily deep child structure. One thing that makes components different than standard prototypal classes is that you don't need to call new on them. They are convenience wrappers that construct backing instances (via new) for you.
|
||||
|
||||
For more information about the specification object, see [Component Specs and Lifecycle](component-specs.html).
|
||||
For more information about the specification object, see [Component Specs and Lifecycle](/react/docs/component-specs.html).
|
||||
|
||||
|
||||
### React.renderComponent
|
||||
@@ -46,7 +75,7 @@ ReactComponent renderComponent(
|
||||
)
|
||||
```
|
||||
|
||||
Renders a React component into the DOM in the supplied `container`.
|
||||
Render a React component into the DOM in the supplied `container` and return a reference to the component.
|
||||
|
||||
If the React component was previously rendered into `container`, this will perform an update on it and only mutate the DOM as necessary to reflect the latest React component.
|
||||
|
||||
@@ -56,10 +85,10 @@ If the optional callback is provided, it will be executed after the component is
|
||||
### React.unmountComponentAtNode
|
||||
|
||||
```javascript
|
||||
unmountComponentAtNode(DOMElement container)
|
||||
boolean unmountComponentAtNode(DOMElement container)
|
||||
```
|
||||
|
||||
Remove a mounted React component from the DOM and clean up its event handlers and state.
|
||||
Remove a mounted React component from the DOM and clean up its event handlers and state. If no component was mounted in the container, calling this function does nothing. Returns `true` if a component was unmounted and `false` if there was no component to unmount.
|
||||
|
||||
> Note:
|
||||
>
|
||||
@@ -69,9 +98,18 @@ Remove a mounted React component from the DOM and clean up its event handlers an
|
||||
### React.renderComponentToString
|
||||
|
||||
```javascript
|
||||
renderComponentToString(ReactComponent component, function callback)
|
||||
string renderComponentToString(ReactComponent component)
|
||||
```
|
||||
|
||||
Render a component to its initial HTML. This should only be used on the server. React will call `callback` with an HTML string when the markup is ready. You can use this method to can generate HTML on the server and send the markup down on the initial request for faster page loads and to allow search engines to crawl your pages for SEO purposes.
|
||||
Render a component to its initial HTML. This should only be used on the server. React will return an HTML string. You can use this method to generate HTML on the server and send the markup down on the initial request for faster page loads and to allow search engines to crawl your pages for SEO purposes.
|
||||
|
||||
If you call `React.renderComponent()` on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
|
||||
|
||||
|
||||
### React.renderComponentToStaticMarkup
|
||||
|
||||
```javascript
|
||||
string renderComponentToStaticMarkup(ReactComponent component)
|
||||
```
|
||||
|
||||
Similar to `renderComponentToString`, except this doesn't create extra DOM attributes such as `data-react-id`, that React uses internally. This is useful if you want to use React as a simple static page generator, as stripping away the extra attributes can save lots of bytes.
|
||||
|
||||
@@ -9,7 +9,7 @@ next: component-specs.html
|
||||
|
||||
## ReactComponent
|
||||
|
||||
Component classses created by `createClass()` return instances of `ReactComponent` when called. Most of the time when you're using React you're either creating or consuming these component objects.
|
||||
Component classes created by `React.createClass()` return instances of `ReactComponent` when called. Most of the time when you're using React you're either creating or consuming these component objects.
|
||||
|
||||
|
||||
### getDOMNode
|
||||
@@ -24,20 +24,24 @@ If this component has been mounted into the DOM, this returns the corresponding
|
||||
### setProps
|
||||
|
||||
```javascript
|
||||
setProps(object nextProps)
|
||||
setProps(object nextProps[, function callback])
|
||||
```
|
||||
|
||||
When you're integrating with an external JavaScript application you may want to signal a change to a React component rendered with `renderComponent()`. Simply call `setProps()` to change its properties and trigger a re-render.
|
||||
When you're integrating with an external JavaScript application you may want to signal a change to a React component rendered with `React.renderComponent()`.
|
||||
|
||||
Though calling `React.renderComponent()` again on the same node is the preferred way to update a root-level component, you can also call `setProps()` to change its properties and trigger a re-render. In addition, you can supply an optional callback function that is executed once `setProps` is completed and the component is re-rendered.
|
||||
|
||||
> Note:
|
||||
>
|
||||
> This method can only be called on a root-level component. That is, it's only available on the component passed directly to `renderComponent()` and none of its children. If you're inclined to use `setProps()` on a child component, instead take advantage of reactive updates and pass the new prop to the child component when it's created in `render()`.
|
||||
> When possible, the declarative approach of calling `React.renderComponent()` again is preferred; it tends to make updates easier to reason about. (There's no significant performance difference between the two approaches.)
|
||||
>
|
||||
> This method can only be called on a root-level component. That is, it's only available on the component passed directly to `React.renderComponent()` and none of its children. If you're inclined to use `setProps()` on a child component, instead take advantage of reactive updates and pass the new prop to the child component when it's created in `render()`.
|
||||
|
||||
|
||||
### replaceProps
|
||||
|
||||
```javascript
|
||||
replaceProps(object nextProps)
|
||||
replaceProps(object nextProps[, function callback])
|
||||
```
|
||||
|
||||
Like `setProps()` but deletes any pre-existing props instead of merging the two objects.
|
||||
@@ -76,7 +80,7 @@ Properties that are specified directly on the target component instance (such as
|
||||
setState(object nextState[, function callback])
|
||||
```
|
||||
|
||||
Merges nextState with the current state. This is the primary method you use to trigger UI updates from event handlers and server request callbacks. In addition, you can supply an optional callback function that is executed once `setState` is completed.
|
||||
Merges nextState with the current state. This is the primary method you use to trigger UI updates from event handlers and server request callbacks. In addition, you can supply an optional callback function that is executed once `setState` is completed and the component is re-rendered.
|
||||
|
||||
> Notes:
|
||||
>
|
||||
@@ -107,3 +111,12 @@ If your `render()` method reads from something other than `this.props` or `this.
|
||||
Calling `forceUpdate()` will cause `render()` to be called on the component and its children, but React will still only update the DOM if the markup changes.
|
||||
|
||||
Normally you should try to avoid all uses of `forceUpdate()` and only read from `this.props` and `this.state` in `render()`. This makes your application much simpler and more efficient.
|
||||
|
||||
|
||||
### isMounted()
|
||||
|
||||
```javascript
|
||||
bool isMounted()
|
||||
```
|
||||
|
||||
`isMounted()` returns true if the component is rendered into the DOM, false otherwise. You can use this method to guard asynchronous calls to `setState()` or `forceUpdate()`.
|
||||
|
||||
@@ -20,7 +20,7 @@ ReactComponent render()
|
||||
|
||||
The `render()` method is required.
|
||||
|
||||
When called, it should examine `this.props` and `this.state` and return a single child component. This child component can be either a native DOM component (such as `<div>`) or another composite component that you've defined yourself.
|
||||
When called, it should examine `this.props` and `this.state` and return a single child component. This child component can be either a virtual representation of a native DOM component (such as `<div />` or `React.DOM.div()`) or another composite component that you've defined yourself.
|
||||
|
||||
The `render()` function should be *pure*, meaning that it does not modify component state, it returns the same result each time it's invoked, and it does not read from or write to the DOM or otherwise interact with the browser (e.g., by using `setTimeout`). If you need to interact with the browser, perform your work in `componentDidMount()` or the other lifecycle methods instead. Keeping `render()` pure makes server rendering more practical and makes components easier to think about.
|
||||
|
||||
@@ -51,7 +51,7 @@ This method is invoked before `getInitialState` and therefore cannot rely on `th
|
||||
object propTypes
|
||||
```
|
||||
|
||||
The `propTypes` object allows you to validate props being passed to your components. For more information about `propTypes`, see [Reusable Components](reusable-components.html).
|
||||
The `propTypes` object allows you to validate props being passed to your components. For more information about `propTypes`, see [Reusable Components](/react/docs/reusable-components.html).
|
||||
|
||||
<!-- TODO: Document propTypes here directly. -->
|
||||
|
||||
@@ -62,11 +62,45 @@ The `propTypes` object allows you to validate props being passed to your compone
|
||||
array mixins
|
||||
```
|
||||
|
||||
The `mixins` array allows you to use mixins to share behavior among multiple components. For more information about mixins, see [Reusable Components](reusable-components.html).
|
||||
The `mixins` array allows you to use mixins to share behavior among multiple components. For more information about mixins, see [Reusable Components](/react/docs/reusable-components.html).
|
||||
|
||||
<!-- TODO: Document mixins here directly. -->
|
||||
|
||||
|
||||
### statics
|
||||
|
||||
```javascript
|
||||
object statics
|
||||
```
|
||||
|
||||
The `statics` object allows you to define static methods that can be called on the component class. For example:
|
||||
|
||||
```javascript
|
||||
var MyComponent = React.createClass({
|
||||
statics: {
|
||||
customMethod: function(foo) {
|
||||
return foo === 'bar';
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
});
|
||||
|
||||
MyComponent.customMethod('bar'); // true
|
||||
```
|
||||
|
||||
Methods defined within this block are _static_, meaning that you can run them before any component instances are created, and the methods do not have access to the props or state of your components. If you want to check the value of props in a static method, have the caller pass in the props as an argument to the static method.
|
||||
|
||||
|
||||
### displayName
|
||||
|
||||
```javascript
|
||||
string displayName
|
||||
```
|
||||
|
||||
The `displayName` string is used in debugging messages. JSX sets this value automatically, see [JSX in Depth](/react/docs/jsx-in-depth.html#react-composite-components).
|
||||
|
||||
|
||||
## Lifecycle Methods
|
||||
|
||||
Various methods are executed at specific points in a component's lifecycle.
|
||||
@@ -78,19 +112,23 @@ Various methods are executed at specific points in a component's lifecycle.
|
||||
componentWillMount()
|
||||
```
|
||||
|
||||
Invoked immediately before rendering occurs. If you call `setState` within this method, `render()` will see the updated state and will be executed only once despite the state change.
|
||||
Invoked once, immediately before the initial rendering occurs. If you call `setState` within this method, `render()` will see the updated state and will be executed only once despite the state change.
|
||||
|
||||
|
||||
### Mounting: componentDidMount
|
||||
|
||||
```javascript
|
||||
componentDidMount(DOMElement rootNode)
|
||||
componentDidMount()
|
||||
```
|
||||
|
||||
Invoked immediately after rendering occurs. At this point in the lifecycle, the component has a DOM representation which you can access via the `rootNode` argument or by calling `this.getDOMNode()`.
|
||||
Invoked immediately after rendering occurs. At this point in the lifecycle, the component has a DOM representation which you can access via `this.getDOMNode()`.
|
||||
|
||||
If you want to integrate with other JavaScript frameworks, set timers using `setTimeout` or `setInterval`, or send AJAX requests, perform those operations in this method.
|
||||
|
||||
> Note:
|
||||
>
|
||||
> Prior to v0.9, the DOM node was passed in as the last argument. If you were using this, you can still access the DOM node by calling `this.getDOMNode()`.
|
||||
|
||||
|
||||
### Updating: componentWillReceiveProps
|
||||
|
||||
@@ -157,13 +195,17 @@ Use this as an opportunity to perform preparation before an update occurs.
|
||||
### Updating: componentDidUpdate
|
||||
|
||||
```javascript
|
||||
componentDidUpdate(object prevProps, object prevState, DOMElement rootNode)
|
||||
componentDidUpdate(object prevProps, object prevState)
|
||||
```
|
||||
|
||||
Invoked immediately after updating occurs. This method is not called for the initial render.
|
||||
|
||||
Use this as an opportunity to operate on the DOM when the component has been updated.
|
||||
|
||||
> Note:
|
||||
>
|
||||
> Prior to v0.9, the DOM node was passed in as the last argument. If you were using this, you can still access the DOM node by calling `this.getDOMNode()`.
|
||||
|
||||
|
||||
### Unmounting: componentWillUnmount
|
||||
|
||||
|
||||
@@ -11,28 +11,32 @@ next: events.html
|
||||
|
||||
React attempts to support all common elements. If you need an element that isn't listed here, please file an issue.
|
||||
|
||||
The following elements are supported:
|
||||
|
||||
|
||||
### HTML Elements
|
||||
|
||||
The following HTML elements are supported:
|
||||
|
||||
```
|
||||
a abbr address area article aside audio b base bdi bdo big blockquote body br
|
||||
button canvas caption cite code col colgroup data datalist dd del details dfn
|
||||
div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6
|
||||
head header hr html i iframe img input ins kbd keygen label legend li link main
|
||||
map mark menu menuitem meta meter nav noscript object ol optgroup option output
|
||||
p param pre progress q rp rt ruby s samp script section select small source
|
||||
span strong style sub summary sup table tbody td textarea tfoot th thead time
|
||||
title tr track u ul var video wbr
|
||||
head header hr html i iframe img input ins kbd keygen label legend li link
|
||||
main map mark menu menuitem meta meter nav noscript object ol optgroup option
|
||||
output p param pre progress q rp rt ruby s samp script section select small
|
||||
source span strong style sub summary sup table tbody td textarea tfoot th
|
||||
thead time title tr track u ul var video wbr
|
||||
```
|
||||
|
||||
### SVG elements
|
||||
|
||||
The following SVG elements are supported:
|
||||
|
||||
```
|
||||
circle g line path polyline rect svg text
|
||||
circle defs g line linearGradient path polygon polyline radialGradient rect
|
||||
stop svg text
|
||||
```
|
||||
|
||||
You may also be interested in [react-art](https://github.com/facebook/react-art), a drawing library for React that can render to Canvas, SVG, or VML (for IE8).
|
||||
|
||||
|
||||
## Supported Attributes
|
||||
|
||||
@@ -42,27 +46,32 @@ React supports all `data-*` and `aria-*` attributes as well as every attribute i
|
||||
>
|
||||
> All attributes are camel-cased and the attributes `class` and `for` are `className` and `htmlFor`, respectively, to match the DOM API specification.
|
||||
|
||||
For a list of events, see [Supported Events](events.html).
|
||||
For a list of events, see [Supported Events](/react/docs/events.html).
|
||||
|
||||
### HTML Attributes
|
||||
|
||||
These standard attributes are supported:
|
||||
|
||||
```
|
||||
accept accessKey action allowFullScreen allowTransparency alt autoCapitalize
|
||||
accept accessKey action allowFullScreen allowTransparency alt async
|
||||
autoComplete autoFocus autoPlay cellPadding cellSpacing charSet checked
|
||||
className colSpan content contentEditable contextMenu controls data dateTime
|
||||
dir disabled draggable encType form frameBorder height hidden href htmlFor
|
||||
httpEquiv icon id label lang list max maxLength method min multiple name
|
||||
pattern placeholder poster preload radioGroup readOnly rel required role
|
||||
rowSpan scrollLeft scrollTop selected size spellCheck src step style tabIndex
|
||||
target title type value width wmode
|
||||
className colSpan cols content contentEditable contextMenu controls data
|
||||
dateTime defer dir disabled draggable encType form formNoValidate frameBorder
|
||||
height hidden href htmlFor httpEquiv icon id label lang list loop max
|
||||
maxLength method min multiple name noValidate pattern placeholder poster
|
||||
preload radioGroup readOnly rel required role rowSpan rows sandbox scope
|
||||
scrollLeft scrollTop seamless selected size span spellCheck src srcDoc step
|
||||
style tabIndex target title type value width wmode
|
||||
```
|
||||
|
||||
In addition, the non-standard `autoCapitalize` attribute is supported for Mobile Safari.
|
||||
In addition, the non-standard `autoCapitalize` and `autoCorrect` attributes are supported for Mobile Safari, and the `property` attribute is supported for Open Graph `<meta>` tags.
|
||||
|
||||
There is also the React-specific attribute `dangerouslySetInnerHTML` ([more here](/react/docs/special-non-dom-attributes.html)), used for directly inserting HTML strings into a component.
|
||||
|
||||
### SVG Attributes
|
||||
|
||||
```
|
||||
cx cy d fill fx fy gradientTransform gradientUnits offset points r rx ry
|
||||
spreadMethod stopColor stopOpacity stroke strokeLinecap strokeWidth transform
|
||||
spreadMethod stopColor stopOpacity stroke strokeLinecap strokeWidth textAnchor transform
|
||||
version viewBox x1 x2 x y1 y2 y
|
||||
```
|
||||
|
||||
@@ -62,14 +62,16 @@ Properties:
|
||||
|
||||
```javascript
|
||||
boolean altKey
|
||||
String char
|
||||
boolean ctrlKey
|
||||
Number charCode
|
||||
String key
|
||||
Number keyCode
|
||||
String locale
|
||||
Number location
|
||||
boolean metaKey
|
||||
boolean repeat
|
||||
boolean shiftKey
|
||||
Number which
|
||||
```
|
||||
|
||||
|
||||
@@ -96,7 +98,7 @@ Event names:
|
||||
onChange onInput onSubmit
|
||||
```
|
||||
|
||||
For more information about the onChange event, see [Forms](forms.html).
|
||||
For more information about the onChange event, see [Forms](/react/docs/forms.html).
|
||||
|
||||
|
||||
### Mouse Events
|
||||
@@ -106,7 +108,7 @@ Event names:
|
||||
```
|
||||
onClick onDoubleClick onDrag onDragEnd onDragEnter onDragExit onDragLeave
|
||||
onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave
|
||||
onMouseMove onMouseUp
|
||||
onMouseMove onMouseOut onMouseOver onMouseUp
|
||||
```
|
||||
|
||||
Properties:
|
||||
|
||||
@@ -4,11 +4,13 @@ title: DOM Differences
|
||||
layout: docs
|
||||
permalink: dom-differences.html
|
||||
prev: events.html
|
||||
next: special-non-dom-attributes.html
|
||||
---
|
||||
|
||||
React has implemented a browser-independent events and DOM system for performance and cross-browser compatibility reasons. We took the opportunity to clean up a few rough edges in browser DOM implementations.
|
||||
|
||||
* All DOM properties and attributes (including event handlers) should be camelCased to be consistent with standard JavaScript style. We intentionally break with the spec here since the spec is inconsistent.
|
||||
* All DOM properties and attributes (including event handlers) should be camelCased to be consistent with standard JavaScript style. We intentionally break with the spec here since the spec is inconsistent. **However**, `data-*` and `aria-*` attributes [conform to the specs](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#data-*) and should be lower-cased only.
|
||||
* The `style` attribute accepts a JavaScript object with camelCased properties rather than a CSS string. This is consistent with the DOM `style` JavaScript property, is more efficient, and prevents XSS security holes.
|
||||
* All event objects conform to the W3C spec, and all events (including submit) bubble correctly per the W3C spec. See [Event System](events.html) for more details.
|
||||
* The `onChange` event behaves as you would expect it to: whenever a form field is changed this event is fired rather than inconsistently on blur. We intentionally break from existing browser behavior because `onChange` is a misnomer for its behavior and React relies on this event to react to user input in real time. See [Forms](forms.html) for more details.
|
||||
* All event objects conform to the W3C spec, and all events (including submit) bubble correctly per the W3C spec. See [Event System](/react/docs/events.html) for more details.
|
||||
* The `onChange` event behaves as you would expect it to: whenever a form field is changed this event is fired rather than inconsistently on blur. We intentionally break from existing browser behavior because `onChange` is a misnomer for its behavior and React relies on this event to react to user input in real time. See [Forms](/react/docs/forms.html) for more details.
|
||||
* Form input attributes such as `value` and `checked`, as well as `textarea`. [More here](/react/docs/forms.html).
|
||||
|
||||
14
docs/docs/ref-07-special-non-dom-attributes.md
Normal file
14
docs/docs/ref-07-special-non-dom-attributes.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
id: special-non-dom-attributes
|
||||
title: Special Non-DOM Attributes
|
||||
layout: docs
|
||||
permalink: special-non-dom-attributes.html
|
||||
prev: dom-differences.html
|
||||
next: reconciliation.html
|
||||
---
|
||||
|
||||
Beside [DOM differences](/react/docs/dom-differences.html), React offers some attributes that simply don't exist in DOM.
|
||||
|
||||
- `key`: an optional, unique identifier. When your component shuffles around during `render` passes, it might be destroyed and recreated due to the diff algorithm. Assigning it a key that persists makes sure the component stays. See more [here](/react/docs/multiple-components.html#dynamic-children).
|
||||
- `ref`: see [here](/react/docs/more-about-refs.html).
|
||||
- `dangerouslySetInnerHTML`: takes an object with the key `__html` and a DOM string as value. This is mainly for cooperating with DOM string manipulation libraries. Refer to the last example on the front page.
|
||||
133
docs/docs/ref-08-reconciliation.md
Normal file
133
docs/docs/ref-08-reconciliation.md
Normal file
@@ -0,0 +1,133 @@
|
||||
---
|
||||
id: reconciliation
|
||||
title: Reconciliation
|
||||
layout: docs
|
||||
permalink: reconciliation.html
|
||||
prev: special-non-dom-attributes.html
|
||||
---
|
||||
|
||||
React key design decision is to make the API seem like it re-renders the whole app on every update. This makes writing applications a lot easier but is also an incredible challenge to make it tractable. This article explains how with powerful heuristics we managed to turn a O(n<sup>3</sup>) problem into a O(n) one.
|
||||
|
||||
|
||||
## Motivation
|
||||
|
||||
Generating the minimum number of operations to transform one tree into another is a complex and well-studied problem. The [state of the art algorithms](http://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf) have a complexity in the order of O(n<sup>3</sup>) where n is the number of nodes in the tree.
|
||||
|
||||
This means that displaying 1000 nodes would require in the order of one billion comparisons. This is far too expensive for our use case. To put this number in perspective, CPUs nowadays execute roughly 3 billion instruction per second. So even with the most performant implementation, we wouldn't be able to compute that diff in less than a second.
|
||||
|
||||
Since an optimal algorithm is not tractable, we implement a non-optimal O(n) algorithm using heuristics based on two assumptions:
|
||||
|
||||
1. Two components of the same class will generate similar trees and two components of different classes will generate different trees.
|
||||
2. It is possible to provide a unique key for elements that is stable across different renders.
|
||||
|
||||
In practice, these assumptions are ridiculously fast for almost all practical use cases.
|
||||
|
||||
|
||||
## Pair-wise diff
|
||||
|
||||
In order to do a tree diff, we first need to be able to diff two nodes. There are three different cases being handled.
|
||||
|
||||
|
||||
### Different Node Types
|
||||
|
||||
If the node type is different, React is going to treat them as two different sub-trees, throw away the first one and build/insert the second one.
|
||||
|
||||
```xml
|
||||
renderA: <div />
|
||||
renderB: <span />
|
||||
=> [removeNode <div />], [insertNode <span />]
|
||||
```
|
||||
|
||||
The same logic is used for custom components. If they are not of the same type, React is not going to even try at matching what they render. It is just going to remove the first one from the DOM and insert the second one.
|
||||
|
||||
```xml
|
||||
renderA: <Header />
|
||||
renderB: <Content />
|
||||
=> [removeNode <Header />], [insertNode <Content />]
|
||||
```
|
||||
|
||||
Having this high level knowledge is a very important aspect of why React diff algorithm is both fast and precise. It provides a good heuristic to quickly prune big parts of the tree and focus on parts likely to be similar.
|
||||
|
||||
It is very unlikely that a `<Header>` element is going generate a DOM that is going to look like what a `<Content>` would generate. Instead of spending time trying to match those two structures, React just re-builds the tree from scratch.
|
||||
|
||||
As a corollary, if there is a `<Header>` element at the same position in two consecutive renders, you would expect to see a very similar structure and it is worth exploring it.
|
||||
|
||||
|
||||
### DOM Nodes
|
||||
|
||||
When comparing two DOM nodes, we look at the attributes of both and can decide which of them changed in linear time.
|
||||
|
||||
```xml
|
||||
renderA: <div id="before" />
|
||||
renderB: <div id="after" />
|
||||
=> [replaceAttribute id "after"]
|
||||
```
|
||||
|
||||
Instead of treating style as an opaque string, a key-value object is used instead. This lets us update only the properties that changed.
|
||||
|
||||
```xml
|
||||
renderA: <div style={{'{{'}}color: 'red'}} />
|
||||
renderB: <div style={{'{{'}}fontWeight: 'bold'}} />
|
||||
=> [removeStyle color], [addStyle font-weight 'bold']
|
||||
```
|
||||
|
||||
After the attributes have been updated, we recurse on all the children.
|
||||
|
||||
|
||||
### Custom Components
|
||||
|
||||
We decided that the two custom components are the same. Since components are stateful, we cannot just use the new component and call it a day. React takes all the attributes from the new component and call `component[Will/Did]ReceiveProps()` on the previous one.
|
||||
|
||||
The previous component is now operational. Its `render()` method is called and the diff algorithm restarts with the new result and the previous result.
|
||||
|
||||
|
||||
## List-wise diff
|
||||
|
||||
### Problematic Case
|
||||
|
||||
In order to do children reconciliation, React adopts a very naive approach. It goes over the list of children both at the same time and whenever there's a difference generates a mutation.
|
||||
|
||||
For example if you add an element at the end:
|
||||
|
||||
```xml
|
||||
renderA: <div><span>first</span></div>
|
||||
renderB: <div><span>first</span><span>second</span></div>
|
||||
=> [insertNode <span>second</span>]
|
||||
```
|
||||
|
||||
Inserting an element at the beginning is problematic. React is going to see that both nodes are spans and therefore run into a mutation mode.
|
||||
|
||||
```xml
|
||||
renderA: <div><span>first</span></div>
|
||||
renderB: <div><span>second</span><span>first</span></div>
|
||||
=> [replaceAttribute textContent 'second'], [insertNode <span>first</span>]
|
||||
```
|
||||
|
||||
There are many algorithms that attempt to find the minimum sets of operations to transform a list of elements. [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance) can find the minimum using single element insertion, deletion and substitution in O(n<sup>2</sup>). Even if we were to use Levenshtein, this doesn't find when a node has moved into another position and algorithms to do that have much worse complexity.
|
||||
|
||||
### Keys
|
||||
|
||||
In order to solve this seemingly intractable issue, an optional attribute has been introduced. You can provide for each child a key that is going to be used to do the matching. If you specify a key, React is now able to find insertion, deletion, substitution and moves in O(n) using a hash table.
|
||||
|
||||
|
||||
```xml
|
||||
renderA: <div><span key="first">first</span></div>
|
||||
renderB: <div><span key="second">second</span><span key="first">first</span></div>
|
||||
=> [insertNode <span>second</span>]
|
||||
```
|
||||
|
||||
In practice, finding a key is not really hard. Most of the time, the element you are going to display already have a unique id. When it is not the case, you can hash some parts of the content to generate an id. Remember that the id only has to be unique among its sibling, not globally unique.
|
||||
|
||||
|
||||
## Trade-offs
|
||||
|
||||
It is important to remember that the reconciliation algorithm is an implementation detail. React could re-render the whole app on every action, the end-result would be the same. We are regularly refining the heuristics in order to make common use cases faster.
|
||||
|
||||
In the current implementation, you can express the fact that a sub-tree has been moved between siblings, but you cannot tell that it has moved somewhere else. The algorithm will re-render that full sub-tree.
|
||||
|
||||
Because we rely on two heuristics, if the assumptions behind them are not met, performance will suffer.
|
||||
|
||||
1. The algorithm will not try to match sub-trees of different components classes. If you see yourself alternating between two components classes with very similar output, you may want to make it the same class. In practice, we haven't found this to be an issue.
|
||||
|
||||
2. If you don't provide stable keys (by using Math.random() for example), all the sub-trees are going to be re-rendered every single time. By giving the users the choice to chose the key, they have the ability to shoot themselves in the foot.
|
||||
|
||||
147
docs/docs/thinking-in-react.md
Normal file
147
docs/docs/thinking-in-react.md
Normal file
@@ -0,0 +1,147 @@
|
||||
---
|
||||
id: thinking-in-react
|
||||
title: Thinking in React
|
||||
layout: docs
|
||||
prev: tutorial.html
|
||||
next: videos.html
|
||||
---
|
||||
|
||||
This was originally a [blog post](/react/blog/2013/11/05/thinking-in-react.html) from the [official React blog](/react/blog).
|
||||
|
||||
React is, in my opinion, the premier way to build big, fast Web apps with JavaScript. It's scaled very well for us at Facebook and Instagram.
|
||||
|
||||
One of the many great parts of React is how it makes you think about apps as you build them. In this post I'll walk you through the thought process of building a searchable product data table using React.
|
||||
|
||||
## Start with a mock
|
||||
|
||||
Imagine that we already have a JSON API and a mock from our designer. Our designer apparently isn't very good because the mock looks like this:
|
||||
|
||||

|
||||
|
||||
Our JSON API returns some data that looks like this:
|
||||
|
||||
```
|
||||
[
|
||||
{category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
|
||||
{category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
|
||||
{category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
|
||||
{category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
|
||||
{category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
|
||||
{category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
|
||||
];
|
||||
```
|
||||
|
||||
## Step 1: break the UI into a component hierarchy
|
||||
|
||||
The first thing you'll want to do is to draw boxes around every component (and subcomponent) in the mock and give them all names. If you're working with a designer they may have already done this, so go talk to them! Their Photoshop layer names may end up being the names of your React components!
|
||||
|
||||
But how do you know what should be its own component? Just use the same techniques for deciding if you should create a new function or object. One such technique is the [single responsibility principle](http://en.wikipedia.org/wiki/Single_responsibility_principle), that is, a component should ideally only do one thing. If it ends up growing it should be decomposed into smaller subcomponents.
|
||||
|
||||
Since you're often displaying a JSON data model to a user, you'll find that if your model was built correctly your UI (and therefore your component structure) will map nicely onto it. That's because user interfaces and data models tend to adhere to the same *information architecture* which means the work of separating your UI into components is often trivial. Just break it up into components that represent exactly one piece of your data model.
|
||||
|
||||

|
||||
|
||||
You'll see here that we have five components in our simple app. I've italicized the data each component represents.
|
||||
|
||||
1. **`FilterableProductTable` (orange):** contains the entirety of the example
|
||||
2. **`SearchBar` (blue):** receives all *user input*
|
||||
3. **`ProductTable` (green):** displays and filters the *data collection* based on *user input*
|
||||
4. **`ProductCategoryRow` (turquoise):** displays a heading for each *category*
|
||||
5. **`ProductRow` (red):** displays a row for each *product*
|
||||
|
||||
If you look at `ProductTable` you'll see that the table header (containing the "Name" and "Price" labels) isn't its own component. This is a matter of preference and there's an argument to be made either way. For this example I left it as part of `ProductTable` because it is part of rendering the *data collection* which is `ProductTable`'s responsibility. However if this header grows to be complex (i.e. if we were to add affordances for sorting) it would certainly make sense to make this its own `ProductTableHeader` component.
|
||||
|
||||
Now that we've identified the components in our mock, let's arrange them into a hierarchy. This is easy. Components that appear within another component in the mock should appear as a child in the hierarchy:
|
||||
|
||||
* `FilterableProductTable`
|
||||
* `SearchBar`
|
||||
* `ProductTable`
|
||||
* `ProductCategoryRow`
|
||||
* `ProductRow`
|
||||
|
||||
## Step 2: Build a static version in React
|
||||
|
||||
<iframe width="100%" height="300" src="http://jsfiddle.net/n25pd/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
|
||||
|
||||
Now that you have your component hierarchy it's time to start implementing your app. The easiest way is to build a version that takes your data model and renders the UI but has no interactivity. It's easiest to decouple these processes because building a static version requires a lot of typing and no thinking, and adding interactivity requires a lot of thinking and not a lot of typing. We'll see why.
|
||||
|
||||
To build a static version of your app that renders your data model you'll want to build components that reuse other components and pass data using *props*. *props* are a way of passing data from parent to child. If you're familiar with the concept of *state*, **don't use state at all** to build this static version. State is reserved only for interactivity, that is, data that changes over time. Since this is a static version of the app you don't need it.
|
||||
|
||||
You can build top-down or bottom-up. That is, you can either start with building the components higher up in the hierarchy (i.e. starting with `FilterableProductTable`) or with the ones lower in it (`ProductRow`). In simpler examples it's usually easier to go top-down and on larger projects it's easier to go bottom-up and write tests as you build.
|
||||
|
||||
At the end of this step you'll have a library of reusable components that render your data model. The components will only have `render()` methods since this is a static version of your app. The component at the top of the hierarchy (`FilterableProductTable`) will take your data model as a prop. If you make a change to your underlying data model and call `renderComponent()` again the UI will be updated. It's easy to see how your UI is updated and where to make changes since there's nothing complicated going on since React's **one-way data flow** (also called *one-way binding*) keeps everything modular, easy to reason about, and fast.
|
||||
|
||||
Simply refer to the [React docs](http://facebook.github.io/react/docs/) if you need help executing this step.
|
||||
|
||||
### A brief interlude: props vs state
|
||||
|
||||
There are two types of "model" data in React: props and state. It's important to understand the distinction between the two; skim [the official React docs](http://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html) if you aren't sure what the difference is.
|
||||
|
||||
## Step 3: Identify the minimal (but complete) representation of UI state
|
||||
|
||||
To make your UI interactive you need to be able to trigger changes to your underlying data model. React makes this easy with **state**.
|
||||
|
||||
To build your app correctly you first need to think of the minimal set of mutable state that your app needs. The key here is DRY: *Don't Repeat Yourself*. Figure out what the absolute minimal representation of the state of your application needs to be and compute everything else you need on-demand. For example, if you're building a TODO list, just keep an array of the TODO items around; don't keep a separate state variable for the count. Instead, when you want to render the TODO count simply take the length of the TODO items array.
|
||||
|
||||
Think of all of the pieces of data in our example application. We have:
|
||||
|
||||
* The original list of products
|
||||
* The search text the user has entered
|
||||
* The value of the checkbox
|
||||
* The filtered list of products
|
||||
|
||||
Let's go through each one and figure out which one is state. Simply ask three questions about each piece of data:
|
||||
|
||||
1. Is it passed in from a parent via props? If so, it probably isn't state.
|
||||
2. Does it change over time? If not, it probably isn't state.
|
||||
3. Can you compute it based on any other state or props in your component? If so, it's not state.
|
||||
|
||||
The original list of products is passed in as props, so that's not state. The search text and the checkbox seem to be state since they change over time and can't be computed from anything. And finally, the filtered list of products isn't state because it can be computed by combining the original list of products with the search text and value of the checkbox.
|
||||
|
||||
So finally, our state is:
|
||||
|
||||
* The search text the user has entered
|
||||
* The value of the checkbox
|
||||
|
||||
## Step 4: Identify where your state should live
|
||||
|
||||
<iframe width="100%" height="300" src="http://jsfiddle.net/t53sx/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
|
||||
|
||||
OK, so we've identified what the minimal set of app state is. Next we need to identify which component mutates, or *owns*, this state.
|
||||
|
||||
Remember: React is all about one-way data flow down the component hierarchy. It may not be immediately clear which component should own what state. **This is often the most challenging part for newcomers to understand,** so follow these steps to figure it out:
|
||||
|
||||
For each piece of state in your application:
|
||||
|
||||
* Identify every component that renders something based on that state.
|
||||
* Find a common owner component (a single component above all the components that need the state in the hierarchy).
|
||||
* Either the common owner or another component higher up in the hierarchy should own the state.
|
||||
* If you can't find a component where it makes sense to own the state, create a new component simply for holding the state and add it somewhere in the hierarchy above the common owner component.
|
||||
|
||||
Let's run through this strategy for our application:
|
||||
|
||||
* `ProductTable` needs to filter the product list based on state and `SearchBar` needs to display the search text and checked state.
|
||||
* The common owner component is `FilterableProductTable`.
|
||||
* It conceptually makes sense for the filter text and checked value to live in `FilterableProductTable`
|
||||
|
||||
Cool, so we've decided that our state lives in `FilterableProductTable`. First, add a `getInitialState()` method to `FilterableProductTable` that returns `{filterText: '', inStockOnly: false}` to reflect the initial state of your application. Then pass `filterText` and `inStockOnly` to `ProductTable` and `SearchBar` as a prop. Finally, use these props to filter the rows in `ProductTable` and set the values of the form fields in `SearchBar`.
|
||||
|
||||
You can start seeing how your application will behave: set `filterText` to `"ball"` and refresh your app. You'll see the data table is updated correctly.
|
||||
|
||||
## Step 5: Add inverse data flow
|
||||
|
||||
<iframe width="100%" height="300" src="http://jsfiddle.net/F8H7p/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
|
||||
|
||||
So far we've built an app that renders correctly as a function of props and state flowing down the hierarchy. Now it's time to support data flowing the other way: the form components deep in the hierarchy need to update the state in `FilterableProductTable`.
|
||||
|
||||
React makes this data flow explicit to make it easy to understand how your program works, but it does require a little more typing than traditional two-way data binding. React provides an add-on called `ReactLink` to make this pattern as convenient as two-way binding, but for the purpose of this post we'll keep everything explicit.
|
||||
|
||||
If you try to type or check the box in the current version of the example you'll see that React ignores your input. This is intentional, as we've set the `value` prop of the `input` to always be equal to the `state` passed in from `FilterableProductTable`.
|
||||
|
||||
Let's think about what we want to happen. We want to make sure that whenever the user changes the form we update the state to reflect the user input. Since components should only update their own state, `FilterableProductTable` will pass a callback to `SearchBar` that will fire whenever the state should be updated. We can use the `onChange` event on the inputs to be notified of it. And the callback passed by `FilterableProductTable` will call `setState()` and the app will be updated.
|
||||
|
||||
Though this sounds like a lot it's really just a few lines of code. And it's really explicit how your data is flowing throughout the app.
|
||||
|
||||
## And that's it
|
||||
|
||||
Hopefully this gives you an idea of how to think about building components and applications with React. While it may be a little more typing than you're used to, remember that code is read far more than it's written, and it's extremely easy to read this modular, explicit code. As you start to build large libraries of components you'll appreciate this explicitness and modularity, and with code reuse your lines of code will start to shrink :)
|
||||
@@ -2,8 +2,11 @@
|
||||
id: tutorial
|
||||
title: Tutorial
|
||||
layout: docs
|
||||
prev: getting-started.html
|
||||
next: thinking-in-react.html
|
||||
---
|
||||
We'll be building a simple, but realistic comments box that you can drop into a blog, similar to Disqus, LiveFyre or Facebook comments.
|
||||
|
||||
We'll be building a simple, but realistic comments box that you can drop into a blog, a basic version of the realtime comments offered by Disqus, LiveFyre or Facebook comments.
|
||||
|
||||
We'll provide:
|
||||
|
||||
@@ -19,7 +22,7 @@ It'll also have a few neat features:
|
||||
|
||||
### Want to skip all this and just see the source?
|
||||
|
||||
[It's all on GitHub.](https://github.com/petehunt/react-tutorial)
|
||||
[It's all on GitHub.](https://github.com/reactjs/react-tutorial)
|
||||
|
||||
### Getting started
|
||||
|
||||
@@ -32,13 +35,13 @@ For this tutorial we'll use prebuilt JavaScript files on a CDN. Open up your fav
|
||||
<title>Hello React</title>
|
||||
<script src="http://fb.me/react-{{site.react_version}}.js"></script>
|
||||
<script src="http://fb.me/JSXTransformer-{{site.react_version}}.js"></script>
|
||||
<script src="http://code.jquery.com/jquery-1.10.0.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script type="text/jsx">
|
||||
/**
|
||||
* @jsx React.DOM
|
||||
*/
|
||||
/** @jsx React.DOM */
|
||||
// The above declaration must remain intact at the top of the script.
|
||||
// Your code here
|
||||
</script>
|
||||
</body>
|
||||
@@ -86,10 +89,9 @@ The first thing you'll notice is the XML-ish syntax in your JavaScript. We have
|
||||
var CommentBox = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
React.DOM.div({
|
||||
className: 'commentBox',
|
||||
children: 'Hello, world! I am a CommentBox.'
|
||||
})
|
||||
React.DOM.div({className: "commentBox"},
|
||||
"Hello, world! I am a CommentBox."
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -99,7 +101,7 @@ React.renderComponent(
|
||||
);
|
||||
```
|
||||
|
||||
Its use is optional but we've found JSX syntax easier to use than plain JavaScript. Read more on the [JSX Syntax article](jsx-in-depth.html).
|
||||
Its use is optional but we've found JSX syntax easier to use than plain JavaScript. Read more on the [JSX Syntax article](/react/docs/jsx-in-depth.html).
|
||||
|
||||
#### What's going on
|
||||
|
||||
@@ -205,12 +207,13 @@ Markdown is a simple way to format your text inline. For example, surrounding te
|
||||
|
||||
First, add the third-party **Showdown** library to your application. This is a JavaScript library which takes Markdown text and converts it to raw HTML. This requires a script tag in your head (which we have already included in the React playground):
|
||||
|
||||
```html{6}
|
||||
```html{7}
|
||||
<!-- template.html -->
|
||||
<head>
|
||||
<title>Hello React</title>
|
||||
<script src="http://fb.me/react-{{site.react_version}}.js"></script>
|
||||
<script src="http://fb.me/JSXTransformer-{{site.react_version}}.js"></script>
|
||||
<script src="http://code.jquery.com/jquery-1.10.0.min.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
|
||||
</head>
|
||||
```
|
||||
@@ -298,12 +301,16 @@ React.renderComponent(
|
||||
|
||||
Now that the data is available in the `CommentList`, let's render the comments dynamically:
|
||||
|
||||
```javascript{4-6}
|
||||
```javascript{4-10,13}
|
||||
// tutorial10.js
|
||||
var CommentList = React.createClass({
|
||||
render: function() {
|
||||
var commentNodes = this.props.data.map(function (comment) {
|
||||
return <Comment author={comment.author}>{comment.text}</Comment>;
|
||||
return (
|
||||
<Comment author={comment.author}>
|
||||
{comment.text}
|
||||
</Comment>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<div className="commentList">
|
||||
@@ -320,7 +327,7 @@ That's it!
|
||||
|
||||
Let's replace the hard-coded data with some dynamic data from the server. We will remove the data prop and replace it with a URL to fetch:
|
||||
|
||||
```javascript{2}
|
||||
```javascript{3}
|
||||
// tutorial11.js
|
||||
React.renderComponent(
|
||||
<CommentBox url="comments.json" />,
|
||||
@@ -369,21 +376,27 @@ When the component is first created, we want to GET some JSON from the server an
|
||||
]
|
||||
```
|
||||
|
||||
We will use jQuery to help make an asynchronous request to the server.
|
||||
We'll use jQuery to help make an asynchronous request to the server.
|
||||
|
||||
Note: because this is becoming an AJAX application you'll need to develop your app using a web server rather than as a file sitting on your file system. The easiest way to do this is to run `python -m SimpleHTTPServer` in your application's directory.
|
||||
|
||||
```javascript{4-11}
|
||||
```javascript{6-17}
|
||||
// tutorial13.js
|
||||
var CommentBox = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {data: []};
|
||||
},
|
||||
componentWillMount: function() {
|
||||
$.ajax({
|
||||
url: 'comments.json',
|
||||
url: this.props.url,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
this.setState({data: data});
|
||||
}.bind(this),
|
||||
error: function(xhr, status, err) {
|
||||
console.error(this.props.url, status, err.toString());
|
||||
}.bind(this)
|
||||
});
|
||||
return {data: []};
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
@@ -397,16 +410,20 @@ var CommentBox = React.createClass({
|
||||
});
|
||||
```
|
||||
|
||||
The key is the call to `this.setState()`. We replace the old array of comments with the new one from the server and the UI automatically updates itself. Because of this reactivity, it is trivial to add live updates. We will use simple polling here but you could easily use WebSockets or other technologies.
|
||||
Here, `componentWillMount` is a method called automatically by React before a component is rendered. The key to dynamic updates is the call to `this.setState()`. We replace the old array of comments with the new one from the server and the UI automatically updates itself. Because of this reactivity, it is only a minor change to add live updates. We will use simple polling here but you could easily use WebSockets or other technologies.
|
||||
|
||||
```javascript{3,17-21,35}
|
||||
```javascript{3,19-20,34}
|
||||
// tutorial14.js
|
||||
var CommentBox = React.createClass({
|
||||
loadCommentsFromServer: function() {
|
||||
$.ajax({
|
||||
url: this.props.url,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
this.setState({data: data});
|
||||
}.bind(this),
|
||||
error: function(xhr, status, err) {
|
||||
console.error(this.props.url, status, err.toString());
|
||||
}.bind(this)
|
||||
});
|
||||
},
|
||||
@@ -458,7 +475,7 @@ var CommentForm = React.createClass({
|
||||
|
||||
Let's make the form interactive. When the user submits the form, we should clear it, submit a request to the server, and refresh the list of comments. To start, let's listen for the form's submit event and clear it.
|
||||
|
||||
```javascript{3-13,16,21}
|
||||
```javascript{3-13,16-18}
|
||||
// tutorial16.js
|
||||
var CommentForm = React.createClass({
|
||||
handleSubmit: function() {
|
||||
@@ -476,11 +493,7 @@ var CommentForm = React.createClass({
|
||||
return (
|
||||
<form className="commentForm" onSubmit={this.handleSubmit}>
|
||||
<input type="text" placeholder="Your name" ref="author" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Say something..."
|
||||
ref="text"
|
||||
/>
|
||||
<input type="text" placeholder="Say something..." ref="text" />
|
||||
<input type="submit" value="Post" />
|
||||
</form>
|
||||
);
|
||||
@@ -504,14 +517,18 @@ When a user submits a comment, we will need to refresh the list of comments to i
|
||||
|
||||
We need to pass data from the child component to its parent. We do this by passing a `callback` in props from parent to child:
|
||||
|
||||
```javascript{13-15,32}
|
||||
```javascript{15-17,30}
|
||||
// tutorial17.js
|
||||
var CommentBox = React.createClass({
|
||||
loadCommentsFromServer: function() {
|
||||
$.ajax({
|
||||
url: this.props.url,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
this.setState({data: data});
|
||||
}.bind(this),
|
||||
error: function(xhr, status, err) {
|
||||
console.error(this.props.url, status, err.toString());
|
||||
}.bind(this)
|
||||
});
|
||||
},
|
||||
@@ -530,9 +547,7 @@ var CommentBox = React.createClass({
|
||||
<div className="commentBox">
|
||||
<h1>Comments</h1>
|
||||
<CommentList data={this.state.data} />
|
||||
<CommentForm
|
||||
onCommentSubmit={this.handleCommentSubmit}
|
||||
/>
|
||||
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -556,11 +571,7 @@ var CommentForm = React.createClass({
|
||||
return (
|
||||
<form className="commentForm" onSubmit={this.handleSubmit}>
|
||||
<input type="text" placeholder="Your name" ref="author" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Say something..."
|
||||
ref="text"
|
||||
/>
|
||||
<input type="text" placeholder="Say something..." ref="text" />
|
||||
<input type="submit" value="Post" />
|
||||
</form>
|
||||
);
|
||||
@@ -570,24 +581,32 @@ var CommentForm = React.createClass({
|
||||
|
||||
Now that the callbacks are in place, all we have to do is submit to the server and refresh the list:
|
||||
|
||||
```javascript{14-22}
|
||||
```javascript{16-27}
|
||||
// tutorial19.js
|
||||
var CommentBox = React.createClass({
|
||||
loadCommentsFromServer: function() {
|
||||
$.ajax({
|
||||
url: this.props.url,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
this.setState({data: data});
|
||||
}.bind(this),
|
||||
error: function(xhr, status, err) {
|
||||
console.error(this.props.url, status, err.toString());
|
||||
}.bind(this)
|
||||
});
|
||||
},
|
||||
handleCommentSubmit: function(comment) {
|
||||
$.ajax({
|
||||
url: this.props.url,
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
data: comment,
|
||||
success: function(data) {
|
||||
this.setState({data: data});
|
||||
}.bind(this),
|
||||
error: function(xhr, status, err) {
|
||||
console.error(this.props.url, status, err.toString());
|
||||
}.bind(this)
|
||||
});
|
||||
},
|
||||
@@ -603,9 +622,7 @@ var CommentBox = React.createClass({
|
||||
<div className="commentBox">
|
||||
<h1>Comments</h1>
|
||||
<CommentList data={this.state.data} />
|
||||
<CommentForm
|
||||
onCommentSubmit={this.handleCommentSubmit}
|
||||
/>
|
||||
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -616,14 +633,18 @@ var CommentBox = React.createClass({
|
||||
|
||||
Our application is now feature complete but it feels slow to have to wait for the request to complete before your comment appears in the list. We can optimistically add this comment to the list to make the app feel faster.
|
||||
|
||||
```javascript{14-16}
|
||||
```javascript{16-18}
|
||||
// tutorial20.js
|
||||
var CommentBox = React.createClass({
|
||||
loadCommentsFromServer: function() {
|
||||
$.ajax({
|
||||
url: this.props.url,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
this.setState({data: data});
|
||||
}.bind(this),
|
||||
error: function(xhr, status, err) {
|
||||
console.error(this.props.url, status, err.toString());
|
||||
}.bind(this)
|
||||
});
|
||||
},
|
||||
@@ -633,10 +654,14 @@ var CommentBox = React.createClass({
|
||||
this.setState({data: newComments});
|
||||
$.ajax({
|
||||
url: this.props.url,
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
data: comment,
|
||||
success: function(data) {
|
||||
this.setState({data: data});
|
||||
}.bind(this),
|
||||
error: function(xhr, status, err) {
|
||||
console.error(this.props.url, status, err.toString());
|
||||
}.bind(this)
|
||||
});
|
||||
},
|
||||
@@ -652,9 +677,7 @@ var CommentBox = React.createClass({
|
||||
<div className="commentBox">
|
||||
<h1>Comments</h1>
|
||||
<CommentList data={this.state.data} />
|
||||
<CommentForm
|
||||
onCommentSubmit={this.handleCommentSubmit}
|
||||
/>
|
||||
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -663,4 +686,4 @@ var CommentBox = React.createClass({
|
||||
|
||||
### Congrats!
|
||||
|
||||
You have just built a comment box in a few simple steps. Learn more about [why to use React](why-react.html), or dive into the [API reference](top-level-api.html) and start hacking! Good luck!
|
||||
You have just built a comment box in a few simple steps. Learn more about [why to use React](/react/docs/why-react.html), or dive into the [API reference](/react/docs/top-level-api.html) and start hacking! Good luck!
|
||||
|
||||
117
docs/docs/videos.md
Normal file
117
docs/docs/videos.md
Normal file
@@ -0,0 +1,117 @@
|
||||
---
|
||||
id: videos
|
||||
title: Videos
|
||||
layout: docs
|
||||
permalink: videos.html
|
||||
prev: thinking-in-react.html
|
||||
next: complementary-tools.html
|
||||
---
|
||||
|
||||
### Rethinking best practices - JSConf.eu
|
||||
|
||||
<iframe width="650" height="315" src="//www.youtube.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
"At Facebook and Instagram, we’re trying to push the limits of what’s possible on the web with React. My talk will start with a brief introduction to the framework, and then dive into three controversial topics: Throwing out the notion of templates and building views with JavaScript, “re-rendering” your entire application when your data changes, and a lightweight implementation of the DOM and events." -- [Pete Hunt](http://www.petehunt.net/)
|
||||
|
||||
|
||||
### Thinking in react - tagtree.tv
|
||||
|
||||
A [tagtree.tv](http://tagtree.tv/) video conveying the principles of [Thinking in React](/react/docs/thinking-in-react.html) while building a simple app
|
||||
<figure>[](http://tagtree.tv/thinking-in-react)</figure>
|
||||
|
||||
|
||||
### Secrets of the Virtual DOM - MtnWest JS
|
||||
|
||||
<iframe width="560" height="315" src="//www.youtube.com/embed/h3KksH8gfcQ" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
"In this talk I’ll be discussing why we built a virtual DOM, how it compares to other systems, and its relevance to the future of browser technologies." -- [Pete Hunt](http://www.petehunt.net/)
|
||||
|
||||
### CodeWinds
|
||||
|
||||
[Pete Hunt](http://www.petehunt.net/) talked with [Jeff Barczewski](http://jeff.barczewski.com/) about React in CodeWinds Episode 4.
|
||||
<figure>[](http://codewinds.com/4)</figure>
|
||||
|
||||
<table width="100%"><tr><td>
|
||||
02:08 - What is React and why use it?<br />
|
||||
03:08 - The symbiotic relationship of ClojureScript and React<br />
|
||||
04:54 - The history of React and why it was created<br />
|
||||
09:43 - Updating web page with React without using data binding<br />
|
||||
13:11 - Using the virtual DOM to change the browser DOM<br />
|
||||
13:57 - Programming with React, render targets HTML, canvas, other<br />
|
||||
16:45 - Working with designers. Contrasted with Ember and AngularJS<br />
|
||||
21:45 - JSX Compiler bridging HTML and React javascript<br />
|
||||
23:50 - Autobuilding JSX and in browser tools for React<br />
|
||||
24:50 - Tips and tricks to working with React, getting started<br />
|
||||
</td><td>
|
||||
27:17 - Rendering HTML on the server with Node.js. Rendering backends<br />
|
||||
29:20 - React evolved through survival of the fittest at Facebook<br />
|
||||
30:15 - Ideas for having state on server and client, using web sockets.<br />
|
||||
32:05 - React-multiuser - distributed shared mutable state using Firebase<br />
|
||||
33:03 - Better debugging with React using the state transitions, replaying events<br />
|
||||
34:08 - Differences from Web Components<br />
|
||||
34:25 - Notable companies using React<br />
|
||||
35:16 - Could a React backend plugin be created to target PDF?<br />
|
||||
36:30 - Future of React, what's next?<br />
|
||||
39:38 - Contributing and getting help<br />
|
||||
</td></tr></table>
|
||||
|
||||
[Read the episode notes](http://codewinds.com/4)
|
||||
|
||||
|
||||
### JavaScript Jabber
|
||||
|
||||
[Pete Hunt](http://www.petehunt.net/) and [Jordan Walke](https://github.com/jordwalke) talked about React in JavaScript Jabber 73.
|
||||
<figure>[](http://javascriptjabber.com/073-jsj-react-with-pete-hunt-and-jordan-walke/#content)</figure>
|
||||
|
||||
<table width="100%"><tr><td>
|
||||
01:34 – Pete Hunt Introduction<br />
|
||||
02:45 – Jordan Walke Introduction<br />
|
||||
04:15 – React<br />
|
||||
06:38 – 60 Frames Per Second<br />
|
||||
09:34 – Data Binding<br />
|
||||
12:31 – Performance<br />
|
||||
17:39 – Diffing Algorithm<br />
|
||||
19:36 – DOM Manipulation
|
||||
</td><td>
|
||||
23:06 – Supporting node.js<br />
|
||||
24:03 – rendr<br />
|
||||
26:02 – JSX<br />
|
||||
30:31 – requestAnimationFrame<br />
|
||||
34:15 – React and Applications<br />
|
||||
38:12 – React Users Khan Academy<br />
|
||||
39:53 – Making it work
|
||||
</td></tr></table>
|
||||
|
||||
[Read the full transcript](http://javascriptjabber.com/073-jsj-react-with-pete-hunt-and-jordan-walke/)
|
||||
|
||||
### Introduction to React.js - Facebook Seattle
|
||||
|
||||
<iframe width="650" height="315" src="//www.youtube.com/embed/XxVg_s8xAms" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
By [Tom Occhino](http://tomocchino.com/) and [Jordan Walke](https://github.com/jordwalke)
|
||||
|
||||
### Developing User Interfaces With React - Super VanJS
|
||||
|
||||
<iframe width="650" height="315" src="//www.youtube.com/embed/1OeXsL5mr4g" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
By [Steven Luscher](https://github.com/steveluscher)
|
||||
|
||||
### Introduction to React - LAWebSpeed meetup
|
||||
|
||||
<iframe width="650" height="315" src="//www.youtube.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
by [Stoyan Stefanov](http://www.phpied.com/)
|
||||
|
||||
### "fun + React + ClojureScript" - Small Talk KyivJS Meetup
|
||||
|
||||
<iframe width="650" height="315" src="//www.youtube.com/embed/R2CGKiNnPFo" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
**In Russian** by [Alexander Solovyov](http://solovyov.net/)
|
||||
|
||||
### "Functional DOM programming" - Meteor DevShop 11
|
||||
|
||||
<iframe width="650" height="315" src="//www.youtube.com/embed/qqVbr_LaCIo" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
### "Rethinking Web App Development at Facebook" - Facebook F8 Conference 2014
|
||||
|
||||
<iframe width="650" height="315" src="//www.youtube.com/embed/nYkdrAPrdcw" frameborder="0" allowfullscreen></iframe>
|
||||
@@ -4,7 +4,7 @@ title: Downloads
|
||||
layout: single
|
||||
---
|
||||
Download the starter kit to get everything you need to
|
||||
[get started with React](/react/docs/getting-started.html).
|
||||
[get started with React](/react/docs/getting-started.html). The starter kit includes React, the in-browser JSX transformer, and some simple example apps.
|
||||
|
||||
<div class="buttons-unit downloads">
|
||||
<a href="/react/downloads/react-{{site.react_version}}.zip" class="button">
|
||||
@@ -12,54 +12,72 @@ Download the starter kit to get everything you need to
|
||||
</a>
|
||||
</div>
|
||||
|
||||
## Development vs. Production Builds
|
||||
|
||||
We provide two versions of React: an uncompressed version for development and a minified version for production. The development version includes extra warnings about common mistakes, whereas the production version includes extra performance optimizations and strips all error messages.
|
||||
|
||||
If you're just starting out, make sure to use the development version.
|
||||
|
||||
## Individual Downloads
|
||||
|
||||
#### <a href="http://fb.me/react-{{site.react_version}}.min.js">React Core {{site.react_version}} (production)</a>
|
||||
The compressed, production version of React core
|
||||
|
||||
```html
|
||||
<script src="http://fb.me/react-{{site.react_version}}.min.js"></script>
|
||||
```
|
||||
|
||||
#### <a href="http://fb.me/react-{{site.react_version}}.js">React Core {{site.react_version}} (development)</a>
|
||||
#### <a href="http://fb.me/react-{{site.react_version}}.js">React {{site.react_version}} (development)</a>
|
||||
The uncompressed, development version of React core with inline documentation.
|
||||
|
||||
```html
|
||||
<script src="http://fb.me/react-{{site.react_version}}.js"></script>
|
||||
```
|
||||
|
||||
#### <a href="http://fb.me/react-with-addons-{{site.react_version}}.min.js">React With Add-Ons {{site.react_version}} (production)</a>
|
||||
The compressed, production version of React with [add-ons](/react/docs/addons.html).
|
||||
#### <a href="http://fb.me/react-{{site.react_version}}.min.js">React {{site.react_version}} (production)</a>
|
||||
The compressed, production version of React core.
|
||||
|
||||
```html
|
||||
<script src="http://fb.me/react-with-addons-{{site.react_version}}.min.js"></script>
|
||||
<script src="http://fb.me/react-{{site.react_version}}.min.js"></script>
|
||||
```
|
||||
|
||||
#### <a href="http://fb.me/react-with-addons-{{site.react_version}}.js">React With Add-Ons {{site.react_version}} (development)</a>
|
||||
#### <a href="http://fb.me/react-with-addons-{{site.react_version}}.js">React with Add-Ons {{site.react_version}} (development)</a>
|
||||
The uncompressed, development version of React with [add-ons](/react/docs/addons.html).
|
||||
|
||||
```html
|
||||
<script src="http://fb.me/react-with-addons-{{site.react_version}}.js"></script>
|
||||
```
|
||||
|
||||
#### <a href="http://fb.me/JSXTransformer-{{site.react_version}}.js">JSX Transform</a>
|
||||
#### <a href="http://fb.me/react-with-addons-{{site.react_version}}.min.js">React with Add-Ons {{site.react_version}} (production)</a>
|
||||
The compressed, production version of React with [add-ons](/react/docs/addons.html).
|
||||
|
||||
```html
|
||||
<script src="http://fb.me/react-with-addons-{{site.react_version}}.min.js"></script>
|
||||
```
|
||||
|
||||
#### <a href="http://fb.me/JSXTransformer-{{site.react_version}}.js">JSX Transformer</a>
|
||||
The JSX transformer used to support [XML syntax](/react/docs/jsx-in-depth.html) in JavaScript.
|
||||
|
||||
```html
|
||||
<script src="http://fb.me/JSXTransformer-{{site.react_version}}.js"></script>
|
||||
```
|
||||
|
||||
All scripts are also available via [CDNJS](http://cdnjs.com/#react).
|
||||
All scripts are also available via [CDNJS](http://cdnjs.com/libraries/react/).
|
||||
|
||||
## npm
|
||||
|
||||
To install the JSX transformer on your computer, run:
|
||||
|
||||
```sh
|
||||
$ npm install -g react-tools
|
||||
```
|
||||
|
||||
For more info about the `jsx` binary, see the [Getting Started](/react/docs/getting-started.html#offline-transform) guide.
|
||||
|
||||
If you're using an npm-compatible packaging system like browserify or webpack, you can use the `react` package. After installing it using `npm install react` or adding `react` to `package.json`, you can use React:
|
||||
|
||||
```js
|
||||
var React = require('react');
|
||||
React.renderComponent(...);
|
||||
```
|
||||
|
||||
If you'd like to use any [add-ons](/react/docs/addons.html), use `var React = require('react/addons');` instead.
|
||||
|
||||
## Bower
|
||||
|
||||
```sh
|
||||
$ bower install --save react
|
||||
```
|
||||
|
||||
## NPM
|
||||
|
||||
```sh
|
||||
$ npm install -g react-tools
|
||||
```
|
||||
|
||||
|
||||
BIN
docs/downloads/react-0.10.0-rc1.zip
Normal file
BIN
docs/downloads/react-0.10.0-rc1.zip
Normal file
Binary file not shown.
BIN
docs/downloads/react-0.10.0.zip
Normal file
BIN
docs/downloads/react-0.10.0.zip
Normal file
Binary file not shown.
BIN
docs/downloads/react-0.11.0-rc1.zip
Normal file
BIN
docs/downloads/react-0.11.0-rc1.zip
Normal file
Binary file not shown.
BIN
docs/downloads/react-0.3.0.zip
Normal file
BIN
docs/downloads/react-0.3.0.zip
Normal file
Binary file not shown.
BIN
docs/downloads/react-0.3.1.zip
Normal file
BIN
docs/downloads/react-0.3.1.zip
Normal file
Binary file not shown.
BIN
docs/downloads/react-0.3.2.zip
Normal file
BIN
docs/downloads/react-0.3.2.zip
Normal file
Binary file not shown.
BIN
docs/downloads/react-0.3.3.zip
Normal file
BIN
docs/downloads/react-0.3.3.zip
Normal file
Binary file not shown.
BIN
docs/downloads/react-0.4.0.zip
Normal file
BIN
docs/downloads/react-0.4.0.zip
Normal file
Binary file not shown.
BIN
docs/downloads/react-0.4.1.zip
Normal file
BIN
docs/downloads/react-0.4.1.zip
Normal file
Binary file not shown.
BIN
docs/downloads/react-0.4.2.zip
Normal file
BIN
docs/downloads/react-0.4.2.zip
Normal file
Binary file not shown.
BIN
docs/downloads/react-0.5.0.zip
Normal file
BIN
docs/downloads/react-0.5.0.zip
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user