Compare commits

...

86 Commits

Author SHA1 Message Date
Paul O’Shannessy
c98c7ccd28 v0.13.2 2015-04-18 15:28:48 -07:00
Paul O’Shannessy
78cca021f3 Update Patent Grant
https://code.facebook.com/posts/1639473982937255/updating-our-open-source-patent-grant/
2015-04-18 15:28:48 -07:00
Paul O’Shannessy
e1437078fc Readme for 0.13.2 2015-04-18 15:28:48 -07:00
Paul O’Shannessy
4f1c61f915 Changelog for 0.13.2 2015-04-18 15:28:48 -07:00
Ben Alpert
4cecb72965 Merge pull request #3675 from spicyj/gh-3655
Add warning for getDefaultProps on ES6 classes
2015-04-17 18:35:19 -07:00
Paul O’Shannessy
db6dcd695f Merge pull request #3485 from jnu/ie10-flex-unitless
Treat flexPositive, flexNegative as unitless styles
2015-04-17 18:35:19 -07:00
Paul O’Shannessy
16cb748161 Update test for backporting #3507 2015-04-17 18:35:19 -07:00
Jim
2e3ac9b683 Merge pull request #3638 from devicehubnet/master
check if type.prototype is object in instantiateReactComponent
2015-04-17 18:35:19 -07:00
Paul O’Shannessy
3509628c22 re-shrinkwrap 2015-04-17 18:35:18 -07:00
Paul O’Shannessy
742d8567e8 Merge pull request #3662 from zpao/update-uglify
Update uglify dependency
2015-04-17 18:35:18 -07:00
Paul O’Shannessy
1c03cd6fd9 Merge pull request #3636 from cody/jsx-target
Add target option to npm readme
2015-04-17 18:35:18 -07:00
Ben Alpert
8b4377ed68 Merge pull request #3627 from spicyj/mut-warn-clone
Refer to cloneElement in mutation warning
2015-04-17 18:35:18 -07:00
Paul O’Shannessy
2c7e818c7c Merge pull request #3618 from TimeBomb/master
Document new es6module flag in react-tools README
2015-04-17 18:35:18 -07:00
Paul O’Shannessy
717ad76529 Merge pull request #3614 from kassens/set_style_null
Fix for style not always reset when set to null
2015-04-17 18:35:18 -07:00
Paul O’Shannessy
9b2176fc23 Merge pull request #3563 from quizlet/fix-addons-hasownproperty
Fix immutability helper to check hasOwnProperty safely
2015-04-17 18:35:18 -07:00
Paul O’Shannessy
7b07d85398 Merge pull request #3519 from jonchester/patch-1
Add IE-specific 'unselectable' attribute
2015-04-17 18:35:18 -07:00
Paul O’Shannessy
6d021d31ef Merge pull request #3513 from agelter/master
Added support for the 'low', 'high', and 'optimum' attributes that are missing from the <meter> tag.
2015-04-17 18:35:18 -07:00
Paul O’Shannessy
ed8b4d6533 Merge pull request #3507 from dpellier/master
Add scoped property to the list of DOM standard properties
2015-04-17 18:35:18 -07:00
Paul O’Shannessy
440d7b9fd0 Merge pull request #3499 from sverrejoh/patch-1
Don't add 'px' to strokeDashoffset CSS Properties
2015-04-17 18:35:17 -07:00
Jim
28483ea245 Merge pull request #3494 from letiemble/B_Context_Rerender
Fix the context handling when updating a rendered component.
2015-04-17 18:35:17 -07:00
Paul O’Shannessy
4d142ad5f1 Version bump for dev 2015-04-17 18:35:17 -07:00
Paul O’Shannessy
4a700aedf8 Merge pull request #3678 from marocchino/update-korean
Update Translation to 6a7a4fd
2015-04-17 18:13:28 -07:00
Paul O’Shannessy
4423200007 Merge pull request #3673 from ultrafez/patch-1
"Advanced performance" typo fix
2015-04-17 18:13:16 -07:00
Jim
f4d7c704dd Merge pull request #3625 from dmin/patch-1
Docs: Fix example JSX output
2015-04-17 18:12:57 -07:00
Christopher Chedeau
fab11d22b8 Update 2015-04-17-react-native-v0.4.md 2015-04-17 09:14:29 -07:00
Christopher Chedeau
c3cf556ca0 React Native 0.4 Blog Post 2015-04-17 09:14:29 -07:00
Ben Alpert
3fd813f752 Merge pull request #3456 from cody/html-jsx
Fix HTML to JSX converter to work with https
2015-04-14 14:43:35 -07:00
Ben Alpert
8109af6d7f Merge pull request #3663 from spicyj/san-md
[docs] Use marked instead of Showdown and escape HTML
(cherry picked from commit be03fa7f46)
2015-04-13 16:46:05 -07:00
Paul O’Shannessy
e0c9fbc9f5 Merge pull request #3658 from sbezludny/patch-1
Fixed typo
2015-04-13 16:12:32 -07:00
Paul O’Shannessy
a1b4f40f9d Merge pull request #3642 from marocchino/ko-update
Update Korean translation to 0185c68
2015-04-13 16:12:32 -07:00
Paul O’Shannessy
aa7eb4302d Merge pull request #3641 from ljharb/patch-1
Updating `es5-shim` URL
2015-04-13 16:12:32 -07:00
Jim
5b18053ac0 Merge pull request #3635 from garethnic/reuseCompDoc
Clarify sentence in Reusable Components doc
2015-04-13 16:12:32 -07:00
Paul O’Shannessy
03595c918a Merge pull request #3584 from ThornWinters/patch-1
More Uniform Formating
2015-04-13 16:12:32 -07:00
Paul O’Shannessy
8680314086 [docs] Fix typo
Introduced in #3589
2015-04-08 10:39:43 -07:00
Paul O’Shannessy
396c6b68ed Merge pull request #3612 from gaearon/patch-1
Mention Flux in “communicate between components”
2015-04-08 10:38:17 -07:00
Ben Alpert
cc8f9d3c30 Merge pull request #3590 from koba04/patch-1
component.render method returns a ReactElement.
2015-04-08 10:38:06 -07:00
Ben Alpert
5daf9f39c0 Merge pull request #3589 from theseyi/master
Documentation: Fixed typo / grammar in 'clone with props'
2015-04-08 10:37:55 -07:00
Ben Alpert
8685fed099 Merge pull request #3588 from marocchino/ko-update
Update Korean translation to d402bd3
2015-04-08 10:36:40 -07:00
Paul O’Shannessy
4bf4112542 Merge pull request #3567 from chenglou/rm-getdomnode
Remove some `getDOMNode` from docs and DOMComponent test
2015-04-03 10:40:52 -07:00
Paul O’Shannessy
ff4c157ed7 Merge pull request #3562 from dalinaum/rename
Rename 19--dangerouslySetInnerHTML.md -> 19-dangerously-set-inner-html.md
2015-04-03 10:40:52 -07:00
Paul O’Shannessy
397fa72d1d Merge pull request #3544 from prathamesh-sonpatki/fix-link-to-display-name
Fixed link to displayName component spec from JSX in depth article
2015-04-03 10:40:52 -07:00
Paul O’Shannessy
b2043987cc Merge pull request #3539 from russellpwirtz/patch-1
Update tutorial.md
2015-04-03 10:40:52 -07:00
Paul O’Shannessy
6343ec5d79 Merge pull request #3537 from marocchino/korean-update
Update Korean translations
2015-04-03 10:40:52 -07:00
Ben Alpert
12b794a3b8 Merge pull request #3529 from uzarubin/patch-1
Swapping defaultChecked and defaultValue
2015-04-03 10:40:52 -07:00
Paul O’Shannessy
449726408e Merge pull request #3511 from AnSavvides/glossary-space
Minor space change to be in line with coding style everywhere else
2015-04-03 10:39:59 -07:00
Paul O’Shannessy
e63149d4f0 Merge pull request #3504 from clariroid/docsJP
Translate 2 docs into Japanese
2015-04-03 10:39:59 -07:00
Paul O’Shannessy
40f77d2715 Merge pull request #3498 from AnSavvides/patch-1
Include latest version of jQuery in tutorial
2015-04-03 10:39:59 -07:00
Paul O’Shannessy
1b4bc922f9 Merge pull request #3491 from bobbyrenwick/transition-group-appear-docs
adding docs for componentWillAppear and componentDidAppear
2015-04-03 10:39:59 -07:00
Paul O’Shannessy
4c779313af Merge pull request #3487 from zpao/doc/video
[docs] Videos: use https, right width videos
2015-04-03 10:39:58 -07:00
Paul O’Shannessy
be13240980 Merge pull request #3483 from julen/docs/document-body-footgun
Docs: do not render components to `document.body`
2015-04-03 10:39:58 -07:00
Paul O’Shannessy
29f11069f3 Merge pull request #3271 from delftswa2014/fix/todo-example
Added the key attribute into the todo example
2015-04-03 10:36:17 -07:00
Paul O’Shannessy
263084f5b7 Merge pull request #3240 from reactkr/translate-ko-release
Korean translation for docs
2015-04-03 10:36:17 -07:00
Ben Alpert
ad02e8bb56 [docs] Fix type on renderIntoDocument
Fixes #3581.

(cherry picked from commit d402bd3831)
2015-04-03 09:12:23 -07:00
Ben Alpert
35bc0f0b41 Fix inverted feature test in .travis.yml
I messed this up in #3540.

(cherry picked from commit 9c12e48f68)
2015-04-01 15:17:46 -07:00
Ahmad Wali Sidiqi
3b5ff0aea7 Fix small typo in 11-advanced-performance.md.
"React didn't even had"->"React didn't even have"

http://english.stackexchange.com/questions/204603/proper-usage-of-didnt-had-or-didnt-have
(cherry picked from commit 4fe1b59849)
2015-03-31 17:03:23 -07:00
Ben Alpert
d77f417767 Squelch git warning on Travis
(cherry picked from commit 835fc3d0fb)
2015-03-30 11:26:14 -07:00
Ben Alpert
946c3f04cc Set name and email a different way
(cherry picked from commit 76805fdfda)
2015-03-30 11:20:34 -07:00
Ben Alpert
d30547792c Set git name and email for Travis
(cherry picked from commit be566e0aa6)
2015-03-30 11:17:49 -07:00
Ben Alpert
6d577d83b8 [docs] English tweaks (and testing Travis)
(cherry picked from commit b7c4da59ca)
2015-03-30 11:11:02 -07:00
Ben Alpert
7f5292bea4 Autobuild website on Travis from stable branch
$REACT_WEBSITE_BRANCH in https://travis-ci.org/facebook/react/settings/env_vars now needs to point to the stable branch (currently 0.13-stable). I haven't tested the commit-and-push part of this but everything else works so I'm hopeful.

(cherry picked from commit accb4f6047)
2015-03-30 10:57:48 -07:00
Ben Alpert
987f243c73 Keep docs/js/{react,JSXTransformer}.js in repo
This way we don't need to rebuild them each time for the website.

(cherry picked from commit 0b6c7c29fe)
2015-03-30 10:57:48 -07:00
Paul O’Shannessy
0a9d6c6bbf Update TravisCI to use exiting env var
$TRAVIS_COMMIT_RANGE was broken but it seems what we're doing is worse and
resulting in false negatives.

The result of the bad range was that we weren't running lint or tests for
things we should have been. It actually looks like $TRAVIS_COMMIT has been
wrong and it's not clear why this has been working at all.

(cherry picked from commit 08b1515f7f)
2015-03-30 10:57:48 -07:00
Christopher Chedeau
54e82a552a Roundup 26 2015-03-30 07:25:14 -07:00
Ben Alpert
65f40df8b5 [docs] Split up second sentence more
(cherry picked from commit eef22ece37)
2015-03-26 12:30:48 -07:00
Ben Alpert
4924cdc436 [docs] Tweak words on homepage
(cherry picked from commit cf956ac8be)
2015-03-26 12:30:48 -07:00
Ben Alpert
67805ed12d Add React Native blog post
(cherry picked from commit 951adcdd4c)
2015-03-26 10:11:10 -07:00
Ben Alpert
5b86aca6ff [docs] Update site nav
(cherry picked from commit ca66399402)
2015-03-26 10:06:38 -07:00
Joseph Savona
d10c8fc1af Merge pull request #3463 from josephsavona/relay-components
Building The Facebook News Feed With Relay
2015-03-19 13:04:22 -07:00
Paul O’Shannessy
9b7de5b196 0.13 blog post, starter kit 2015-03-16 16:54:35 -07:00
Paul O’Shannessy
f308c03455 v0.13.1 2015-03-16 16:50:30 -07:00
Paul O’Shannessy
d4424e87a7 Update Readme for 0.13.1 2015-03-16 16:41:33 -07:00
Paul O’Shannessy
3003dcc0b1 Changelog for 0.13.1 2015-03-16 16:40:40 -07:00
Paul O’Shannessy
8436732a23 Merge pull request #3427 from zpao/full-page-dom-components
Ensure FullPageComponents are treated as DOM components
(cherry picked from commit dacd4db1fa)
2015-03-16 16:27:28 -07:00
Ben Alpert
a82e70ed34 Merge pull request #3414 from spicyj/gh-3407
Fix up Perf a bit better for 0.13
(cherry picked from commit 0a312bba89)
2015-03-16 16:27:28 -07:00
Ben Alpert
2e72fd8e43 Merge pull request #3412 from spicyj/gh-3329
Squash getDOMNode warning from isDOMComponent
(cherry picked from commit ed257cb691)
2015-03-16 16:27:28 -07:00
Ben Alpert
6cc7567eff Merge pull request #3410 from robertknight/3409-style-null-to-nonnull
Fix incorrect update of style when props.style transitions from null to non-null
(cherry picked from commit bcd70ad500)
2015-03-16 16:27:27 -07:00
Paul O’Shannessy
cfbf1d559f Merge pull request #3402 from vkramskikh/fix-empty-selects-with-value
Fix for empty <select> elements with value
(cherry picked from commit 68a2f89cc6)
2015-03-16 16:27:27 -07:00
Paul O’Shannessy
ce9fd5f028 Merge pull request #3381 from zpao/jsx-nonstrictmodule
Fix module option parsing of jsx command
(cherry picked from commit b0a59a643a)
2015-03-16 16:27:27 -07:00
Paul O’Shannessy
9432aceb4d version bump for dev 2015-03-16 16:27:27 -07:00
Paul O’Shannessy
9f95d8793e Merge pull request #3419 from xmo-odoo/patch-1
Link to inserting raw HTML document
2015-03-16 16:24:13 -07:00
Jim
9e0954abdd Merge pull request #3422 from jviereck/doc-typo-fix
Fix small typo ("of" instead of "or")
2015-03-16 16:24:08 -07:00
Paul O’Shannessy
71f65d3da6 Merge pull request #3394 from cody/getDOMNode
Fix in docs: getDOMNode --> findDOMNode
2015-03-16 16:24:03 -07:00
Paul O’Shannessy
fe8d706c1c v0.13 starter kit 2015-03-10 14:47:44 -07:00
Paul O’Shannessy
edb8f7f4af v0.13.0 2015-03-10 14:45:29 -07:00
Paul O’Shannessy
594f816930 Update readme for 0.13 2015-03-10 14:45:29 -07:00
Paul O’Shannessy
94bf54a328 shrinkwrap 2015-03-10 14:45:29 -07:00
157 changed files with 47714 additions and 1498 deletions

View File

@@ -14,6 +14,8 @@ vendor/jasmine-jsreporter/
# But not in docs/_js/examples/*
docs/_js/*.js
docs/js/
# gems
docs/vendor/bundle/
# This should be more like examples/**/thirdparty/** but
# we should fix https://github.com/facebook/esprima/pull/85 first
examples/
examples/

2
.gitignore vendored
View File

@@ -9,11 +9,13 @@ __benchmarks__
build/
.module-cache
*.gem
docs/.bundle
docs/code
docs/_site
docs/.sass-cache
docs/js/*
docs/downloads
docs/vendor/bundle
examples/shared/*.js
test/the-files-to-test.generated.js
*.log*

View File

@@ -5,20 +5,45 @@ node_js:
sudo: false
cache:
directories:
- docs/vendor/bundle
- node_modules
before_install:
- |
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
PR_FIRST=$(curl -s https://github.com/${TRAVIS_REPO_SLUG}/pull/${TRAVIS_PULL_REQUEST}.patch | head -1 | grep -o -E '\b[0-9a-f]{40}\b' | tr -d '\n')
TRAVIS_COMMIT_RANGE=$PR_FIRST^..$TRAVIS_COMMIT
fi
git diff --name-only $TRAVIS_COMMIT_RANGE | grep -qvE '(\.md$)|(^(docs|examples))/' || {
if [ "$TEST_TYPE" != build_website ] && \
! git diff --name-only $TRAVIS_COMMIT_RANGE | grep -qvE '(\.md$)|(^(docs|examples))/'
then
echo "Only docs were updated, stopping build process."
exit
}
fi
script:
- |
grunt $TEST_TYPE
if [ "$TEST_TYPE" = build_website ]; then
if [ "$TRAVIS_BRANCH" = "$REACT_WEBSITE_BRANCH" ] && [ "$TRAVIS_PULL_REQUEST" = false ]; then
set -e
GH_PAGES_DIR="$TRAVIS_BUILD_DIR"/../react-gh-pages
echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" >~/.netrc
git config --global user.name "Travis CI"
git config --global user.email "travis@reactjs.org"
git clone --branch gh-pages --depth=50 \
https://reactjs-bot@github.com/facebook/react.git \
$GH_PAGES_DIR
pushd docs
bundle install --jobs=3 --retry=3 --path=vendor/bundle
bundle exec rake release
cd $GH_PAGES_DIR
git status
if ! git diff-index --quiet HEAD --; then
git add -A .
git commit -m "Rebuild website"
git push origin gh-pages
fi
popd
fi
else
grunt $TEST_TYPE
fi
after_script:
- |
if [ "$TEST_TYPE" = test ] && [ "$SERVER" ]; then
@@ -43,12 +68,15 @@ env:
- TEST_TYPE=test
- TEST_TYPE=jest
- TEST_TYPE=lint
- TEST_TYPE=build_website
- TEST_TYPE=test:webdriver:saucelabs:modern
global:
# SERVER
- secure: qPvsJ46XzGrdIuPA70b55xQNGF8jcK7N1LN5CCQYYocXLa+fBrl+fTE77QvehOPhqwJXcj6kOxI+sY0KrVwV7gmq2XY2HZGWUSCxTN0SZlNIzqPA80Y7G/yOjA4PUt8LKgP+8tptyhTAY56qf+hgW8BoLiKOdztYF2p+3zXOLuA=
# SECRET_TOKEN
- secure: dkpPW+VnoqC/okhRdV90m36NcyBFhcwEKL3bNFExAwi0dXnFao8RoFlvnwiPlA23h2faROkMIetXlti6Aju08BgUFV+f9aL6vLyU7gUent4Nd3413zf2fwDtXIWIETg6uLnOpSykGKgCAT/hY3Q2oPLqOoY0OxfgnbqwxkxljrE=
# GITHUB_TOKEN
- secure: EHCyCSKMwKlLHNtcj9nmkRzmiiPE3aDGlPcnEyrDJeRI0SeN/iCXHXfFivR0vFq3vr+9naMBczAR2AEidtps5KbJrKqdZnjPFRbmfVtzWr/LlvVCub3u13Pub6TdKIVBTny1PuZ5X8GvdxMNVig89jGjvzhhWuQRaz3VhJnTra4=
matrix:
fast_finish: true
allow_failures:

View File

@@ -1,3 +1,57 @@
## 0.13.2 (April 18, 2015)
### React Core
#### New Features
* Added `strokeDashoffset`, `flexPositive`, `flexNegative` to the list of unitless CSS properties
* Added support for more DOM properties:
* `scoped` - for `<style>` elements
* `high`, `low`, `optimum` - for `<meter>` elements
* `unselectable` - IE-specific property to prevent user selection
#### Bug Fixes
* Fixed a case where re-rendering after rendering null didn't properly pass context
* Fixed a case where re-rendering after rendering with `style={null}` didn't properly update `style`
* Update `uglify` dependency to prevent a bug in IE8
* Improved warnings
### React with Add-Ons
#### Bug Fixes
* Immutabilty Helpers: Ensure it supports `hasOwnProperty` as an object key
### React Tools
* Improve documentation for new options
## 0.13.1 (March 16, 2015)
### React Core
#### Bug Fixes
* Don't throw when rendering empty `<select>` elements
* Ensure updating `style` works when transitioning from `null`
### React with Add-Ons
#### Bug Fixes
* TestUtils: Don't warn about `getDOMNode` for ES6 classes
* TestUtils: Ensure wrapped full page components (`<html>`, `<head>`, `<body>`) are treated as DOM components
* Perf: Stop double-counting DOM components
### React Tools
#### Bug Fixes
* Fix option parsing for `--non-strict-es6module`
## 0.13.0 (March 10, 2015)
### React Core

View File

@@ -18,7 +18,6 @@ module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
copy: require('./grunt/config/copy'),
jsx: require('./grunt/config/jsx'),
browserify: require('./grunt/config/browserify'),
populist: require('./grunt/config/populist')(grunt),
@@ -269,7 +268,6 @@ module.exports = function(grunt) {
'npm-react:pack',
'npm-react-tools:release',
'npm-react-tools:pack',
'copy:react_docs',
'compare_size'
]);

46
PATENTS
View File

@@ -1,23 +1,33 @@
Additional Grant of Patent Rights
Additional Grant of Patent Rights Version 2
"Software" means the React software distributed by Facebook, Inc.
Facebook hereby grants you a perpetual, worldwide, royalty-free, non-exclusive,
irrevocable (subject to the termination provision below) license under any
rights in any patent claims owned by Facebook, to make, have made, use, sell,
offer to sell, import, and otherwise transfer the Software. For avoidance of
doubt, no license is granted under Facebooks rights in any patent claims that
are infringed by (i) modifications to the Software made by you or a third party,
or (ii) the Software in combination with any software or other technology
provided by you or a third party.
Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
(subject to the termination provision below) license under any Necessary
Claims, to make, have made, use, sell, offer to sell, import, and otherwise
transfer the Software. For avoidance of doubt, no license is granted under
Facebook's rights in any patent claims that are infringed by (i) modifications
to the Software made by you or any third party or (ii) the Software in
combination with any software or other technology.
The license granted hereunder will terminate, automatically and without notice,
for anyone that makes any claim (including by filing any lawsuit, assertion or
other action) alleging (a) direct, indirect, or contributory infringement or
inducement to infringe any patent: (i) by Facebook or any of its subsidiaries or
affiliates, whether or not such claim is related to the Software, (ii) by any
party if such claim arises in whole or in part from any software, product or
service of Facebook or any of its subsidiaries or affiliates, whether or not
such claim is related to the Software, or (iii) by any party relating to the
Software; or (b) that any right in any patent claim of Facebook is invalid or
unenforceable.
if you (or any of your subsidiaries, corporate affiliates or agents) initiate
directly or indirectly, or take a direct financial interest in, any Patent
Assertion: (i) against Facebook or any of its subsidiaries or corporate
affiliates, (ii) against any party if such Patent Assertion arises in whole or
in part from any software, technology, product or service of Facebook or any of
its subsidiaries or corporate affiliates, or (iii) against any party relating
to the Software. Notwithstanding the foregoing, if Facebook or any of its
subsidiaries or corporate affiliates files a lawsuit alleging patent
infringement against you in the first instance, and you respond by filing a
patent infringement counterclaim in that lawsuit against that party that is
unrelated to the Software, the license granted hereunder will not terminate
under section (i) of this paragraph due to such counterclaim.
A "Necessary Claim" is a claim of a patent owned by Facebook that is
necessarily infringed by the Software standing alone.
A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
or contributory infringement or inducement to infringe any patent, including a
cross-claim or counterclaim.

View File

@@ -1,4 +1,4 @@
# [React](http://facebook.github.io/react) [![Build Status](https://travis-ci.org/facebook/react.svg?branch=master)](https://travis-ci.org/facebook/react)
# [React](http://facebook.github.io/react) [![Build Status](https://travis-ci.org/facebook/react.svg?branch=0.13-stable)](https://travis-ci.org/facebook/react)
React is a JavaScript library for building user interfaces.
@@ -35,12 +35,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.12.2.js"></script>
<script src="http://fb.me/react-0.13.2.js"></script>
<!-- In-browser JSX transformer, remove when pre-compiling JSX. -->
<script src="http://fb.me/JSXTransformer-0.12.2.js"></script>
<script src="http://fb.me/JSXTransformer-0.13.2.js"></script>
```
We've also built a [starter kit](http://facebook.github.io/react/downloads/react-0.12.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.13.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.
If you'd like to use [bower](http://bower.io), it's as easy as:

View File

@@ -44,7 +44,7 @@ require('commoner').version(
sourceMap: this.options.sourceMapInline,
stripTypes: this.options.stripTypes,
es6module: this.options.es6module,
nonStrictEs6Module: this.options.nonStrictEs6Module,
nonStrictEs6module: this.options.nonStrictEs6module,
target: this.options.target
};
return transform(source, options);

View File

@@ -25,13 +25,15 @@ exclude:
- Gemfile.lock
- README.md
- Rakefile
- vendor/bundle
markdown: redcarpet
redcarpet:
extensions:
- fenced_code_blocks
- footnotes
sass:
style: :compressed
sass_dir: _css
gems:
- jekyll-redirect-from
react_version: 0.13.0-rc2
react_version: 0.13.1

View File

@@ -1,12 +1,10 @@
var MARKDOWN_COMPONENT = `
var converter = new Showdown.converter();
var MarkdownEditor = React.createClass({
getInitialState: function() {
return {value: 'Type some *markdown* here!'};
},
handleChange: function() {
this.setState({value: this.refs.textarea.getDOMNode().value});
this.setState({value: React.findDOMNode(this.refs.textarea).value});
},
render: function() {
return (
@@ -20,7 +18,7 @@ var MarkdownEditor = React.createClass({
<div
className="content"
dangerouslySetInnerHTML={{
__html: converter.makeHtml(this.state.value)
__html: marked(this.state.value, {sanitize: true})
}}
/>
</div>

View File

@@ -1,8 +1,8 @@
var TODO_COMPONENT = `
var TodoList = React.createClass({
render: function() {
var createItem = function(itemText) {
return <li>{itemText}</li>;
var createItem = function(itemText, index) {
return <li key={index + itemText}>{itemText}</li>;
};
return <ul>{this.props.items.map(createItem)}</ul>;
}

View File

@@ -21,7 +21,7 @@ var CodeMirrorEditor = React.createClass({
componentDidMount: function() {
if (IS_MOBILE) return;
this.editor = CodeMirror.fromTextArea(this.refs.editor.getDOMNode(), {
this.editor = CodeMirror.fromTextArea(React.findDOMNode(this.refs.editor), {
mode: 'javascript',
lineNumbers: this.props.lineNumbers,
lineWrapping: true,
@@ -194,7 +194,7 @@ var ReactPlayground = React.createClass({
},
executeCode: function() {
var mountNode = this.refs.mount.getDOMNode();
var mountNode = React.findDOMNode(this.refs.mount);
try {
React.unmountComponentAtNode(mountNode);

View File

@@ -33,7 +33,6 @@
<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>
</head>
<body>
@@ -45,12 +44,16 @@
<img class="nav-logo" src="/react/img/logo.svg" width="36" height="36">
React
</a>
<ul class="nav-site">
<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="https://github.com/facebook/react">github</a>
<ul class="nav-site nav-site-internal">
<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>
</ul>
<ul class="nav-site nav-site-external">
<li><a href="https://github.com/facebook/react">GitHub</a>
<li><a href="http://facebook.github.io/react-native/">React Native</a>
</ul>
</div>
</div>

View File

@@ -60,7 +60,7 @@ React.renderComponent(
<option value="Facebook">Facebook</option>
<option value="Harvest">Harvest</option>
</Chosen>
, document.body);
, document.getElementById('example'));
```

View File

@@ -38,7 +38,7 @@ When you name your file with `myfile.js.jsx`, `react-rails` will automatically t
```js
/** @jsx React.DOM */
React.renderComponent(<MyComponent/>, document.body)
React.renderComponent(<MyComponent/>, document.getElementById('example'))
```

View File

@@ -16,7 +16,7 @@ React.renderComponent((
</Route>
</Route>
</Routes>
), document.body);
), document.getElementById('example'));
```
## Going Big with React

View File

@@ -0,0 +1,47 @@
---
title: "React v0.13.1"
author: Paul OShannessy
---
It's been less than a week since we shipped v0.13.0 but it's time to do another quick release. We just released v0.13.1 which contains bugfixes for a number of small issues.
Thanks all of you who have been upgrading your applications and taking the time to report issues. And a huge thank you to those of you who submitted pull requests for the issues you found! 2 of the 6 fixes that went out today came from people who aren't on the core team!
The release is now available for download:
* **React**
Dev build with warnings: <http://fb.me/react-0.13.1.js>
Minified build for production: <http://fb.me/react-0.13.1.min.js>
* **React with Add-Ons**
Dev build with warnings: <http://fb.me/react-with-addons-0.13.1.js>
Minified build for production: <http://fb.me/react-with-addons-0.13.1.min.js>
* **In-Browser JSX transformer**
<http://fb.me/JSXTransformer-0.13.1.js>
We've also published version `0.13.1` of the `react` and `react-tools` packages on npm and the `react` package on bower.
- - -
## Changelog
### React Core
#### Bug Fixes
* Don't throw when rendering empty `<select>` elements
* Ensure updating `style` works when transitioning from `null`
### React with Add-Ons
### Bug Fixes
* TestUtils: Don't warn about `getDOMNode` for ES6 classes
* TestUtils: Ensure wrapped full page components (`<html>`, `<head>`, `<body>`) are treated as DOM components
* Perf: Stop double-counting DOM components
### React Tools
#### Bug Fixes
* Fix option parsing for `--non-strict-es6module`

View File

@@ -0,0 +1,222 @@
---
title: "Building The Facebook News Feed With Relay"
author: Joseph Savona
---
At React.js Conf in January we gave a preview of Relay, a new framework for building data-driven applications in React. In this post we'll describe the process of creating a Relay application. This post assumes some familiarity with the concepts of Relay and GraphQL, so if you haven't already we recommend reading [our introductory blog post](http://facebook.github.io/react/blog/2015/02/20/introducing-relay-and-graphql.html) or watching [the conference talk](https://www.youtube.com/watch?v=9sc8Pyc51uU).
We're working hard to prepare GraphQL and Relay for public release. In the meantime, we'll continue to provide information about what you can expect.
<br/>
## The Relay Architecture
The diagram below shows the main parts of the Relay architecture on the client and the server:
<img src="/react/img/blog/relay-components/relay-architecture.png" alt="Relay Architecture" width="650" />
The main pieces are as follows:
- Relay Components: React components annotated with declarative data descriptions.
- Actions: Descriptions of how data should change in response to user actions.
- Relay Store: A client-side data store that is fully managed by the framework.
- Server: An HTTP server with GraphQL endpoints (one for reads, one for writes) that respond to GraphQL queries.
This post will focus on **Relay components** that describe encapsulated units of UI and their data dependencies. These components form the majority of a Relay application.
<br/>
## A Relay Application
To see how components work and can be composed, let's implement a basic version of the Facebook News Feed in Relay. Our application will have two components: a `<NewsFeed>` that renders a list of `<Story>` items. We'll introduce the plain React version of each component first and then convert it to a Relay component. The goal is something like the following:
<img src="/react/img/blog/relay-components/sample-newsfeed.png" alt="Sample News Feed" width="360" />
<br/>
## The `<Story>` Begins
The first step is a React `<Story>` component that accepts a `story` prop with the story's text and author information. Note that all examples uses ES6 syntax and elide presentation details to focus on the pattern of data access.
```javascript
// Story.react.js
class Story extends React.Component {
render() {
var story = this.props.story;
return (
<View>
<Image uri={story.author.profile_picture.uri} />
<Text>{story.author.name}</Text>
<Text>{story.text}</Text>
</View>
);
}
}
module.exports = Story;
```
<br/>
## What's the `<Story>`?
Relay automates the process of fetching data for components by wrapping existing React components in Relay containers (themselves React components):
```javascript
// Story.react.js
class Story extends React.Component { ... }
module.exports = Relay.createContainer(Story, {
queries: {
story: /* TODO */
}
});
```
Before adding the GraphQL query, let's look at the component hierarchy this creates:
<img src="/react/img/blog/relay-components/relay-containers.png" width="397" alt="React Container Data Flow" />
Most props will be passed through from the container to the original component. However, Relay will return the query results for a prop whenever a query is defined. In this case we'll add a GraphQL query for `story`:
```javascript
// Story.react.js
class Story extends React.Component { ... }
module.exports = Relay.createContainer(Story, {
queries: {
story: graphql`
Story {
author {
name,
profile_picture {
uri
}
},
text
}
`
}
});
```
Queries use ES6 template literals tagged with the `graphql` function. Similar to how JSX transpiles to plain JavaScript objects and function calls, these template literals transpile to plain objects that describe queries. Note that the query's structure closely matches the object structure that we expected in `<Story>`'s render function.
<br/>
## `<Story>`s on Demand
We can render a Relay component by providing Relay with the component (`<Story>`) and the ID of the data (a story ID). Given this information, Relay will first fetch the results of the query and then `render()` the component. The value of `props.story` will be a plain JavaScript object such as the following:
```javascript
{
author: {
name: "Greg",
profile_picture: {
uri: "https://…"
}
},
text: "The first Relay blog post is up…"
}
```
Relay guarantees that all data required to render a component will be available before it is rendered. This means that `<Story>` does not need to handle a loading state; the `story` is *guaranteed* to be available before `render()` is called. We have found that this invariant simplifies our application code *and* improves the user experience. Of course, Relay also has options to delay the fetching of some parts of our queries.
The diagram below shows how Relay containers make data available to our React components:
<img src="/react/img/blog/relay-components/relay-containers-data-flow.png" width="650" alt="Relay Container Data Flow" />
<br/>
## `<NewsFeed>` Worthy
Now that the `<Story>` is over we can continue with the `<NewsFeed>` component. Again, we'll start with a React version:
```javascript
// NewsFeed.react.js
class NewsFeed extends React.Component {
render() {
var stories = this.props.viewer.stories; // `viewer` is the active user
return (
<View>
{stories.map(story => <Story story={story} />)}
<Button onClick={() => this.loadMore()}>Load More</Button>
</View>
);
}
loadMore() {
// TODO: fetch more stories
}
}
module.exports = NewsFeed;
```
<br/>
## All the News Fit to be Relayed
`<NewsFeed>` has two new requirements: it composes `<Story>` and requests more data at runtime.
Just as React views can be nested, Relay queries can compose queries from child components. Composition in GraphQL uses ES6 template literal substitution: `${Component.getQuery('prop')}`. Pagination can be accomplished with a query parameter, specified with `<param>` (as in `stories(first: <count>)`):
```javascript
// NewsFeed.react.js
class NewsFeed extends React.Component { ... }
module.exports = Relay.createContainer(NewsFeed, {
queryParams: {
count: 3 /* default to 3 stories */
},
queries: {
viewer: graphql`
Viewer {
stories(first: <count>) { /* fetch viewer's stories */
edges { /* traverse the graph */
node {
${Story.getQuery('story')} /* compose child query */
}
}
}
}
`
}
});
```
Whenever `<NewsFeed>` is rendered, Relay will recursively expand all the composed queries and fetch them in a single trip to the server. In this case, the `text` and `author` data will be fetched for each of the 3 story nodes.
Query parameters are available to components as `props.queryParams` and can be modified with `props.setQueryParams(nextParams)`. We can use these to implement pagination:
```javascript
// NewsFeed.react.js
class NewsFeed extends React.Component {
render() { ... }
loadMore() {
// read current params
var count = this.props.queryParams.count;
// update params
this.props.setQueryParams({
count: count + 5
});
}
}
```
Now when `loadMore()` is called, Relay will send a GraphQL request for the additional five stories. When these stories are fetched, the component will re-render with the new stories available in `props.viewer.stories` and the updated count reflected in `props.queryParams.count`.
<br/>
## In Conclusion
These two components form a solid core for our application. With the use of Relay containers and GraphQL queries, we've enabled the following benefits:
- Automatic and efficient pre-fetching of data for an entire view hierarchy in a single network request.
- Trivial pagination with automatic optimizations to fetch only the additional items.
- View composition and reusability, so that `<Story>` can be used on its own or within `<NewsFeed>`, without any changes to either component.
- Automatic subscriptions, so that components will re-render if their data changes. Unaffected components will not re-render unnecessarily.
- Exactly *zero* lines of imperative data fetching logic. Relay takes full advantage of React's declarative component model.
But Relay has many more tricks up its sleeve. For example, it's built from the start to handle reads and writes, allowing for features like optimistic client updates with transactional rollback. Relay can also defer fetching select parts of queries, and it uses a local data store to avoid fetching the same data twice. These are all powerful features that we hope to explore in future posts.

View File

@@ -0,0 +1,16 @@
---
title: "Introducing React Native"
author: Ben Alpert
---
In January at React.js Conf, we announced React Native, a new framework for building native apps using React. We're happy to announce that we're open-sourcing React Native and you can start building your apps with it today.
For more details, see [Tom Occhino's post on the Facebook Engineering blog](https://code.facebook.com/posts/1014532261909640/react-native-bringing-modern-web-techniques-to-mobile/):
> *What we really want is the user experience of the native mobile platforms, combined with the developer experience we have when building with React on the web.*
>
> *With a bit of work, we can make it so the exact same React that's on GitHub can power truly native mobile applications. The only difference in the mobile environment is that instead of running React in the browser and rendering to divs and spans, we run it an embedded instance of JavaScriptCore inside our apps and render to higher-level platform-specific components.*
>
> *It's worth noting that we're not chasing “write once, run anywhere.” Different platforms have different looks, feels, and capabilities, and as such, we should still be developing discrete apps for each platform, but the same set of engineers should be able to build applications for whatever platform they choose, without needing to learn a fundamentally different set of technologies for each. We call this approach “learn once, write anywhere.”*
To learn more, visit the [React Native website](http://facebook.github.io/react-native/).

View File

@@ -0,0 +1,95 @@
---
title: "Community Round-up #26"
layout: post
author: Vjeux
---
We open sourced React Native last week and the community reception blew away all our expectations! So many of you tried it, made cool stuff with it, raised many issues and even submitted pull requests to fix them! The entire team wants to say thank you!
<blockquote class="twitter-tweet" lang="en"><p><a href="https://twitter.com/hashtag/reactnative?src=hash">#reactnative</a> is like when you get a new expansion pack, and everybody is running around clueless about which NPC to talk to for the quests</p>&mdash; Ryan Florence (@ryanflorence) <a href="https://twitter.com/ryanflorence/status/581810423554543616">March 28, 2015</a></blockquote>
## When is React Native Android coming?
**Give us 6 months**. At Facebook, we strive to only open-source projects that we are using in production. While the Android backend for React Native is starting to work (see video below at 37min), it hasn't been shipped to any users yet. There's a lot of work that goes into open-sourcing a project, and we want to do it right so that you have a great experience when using it.
<iframe width="560" height="315" src="https://www.youtube.com/embed/X6YbAKiLCLU?start=2220" frameborder="0" allowfullscreen></iframe>
## Ray Wenderlich - Property Finder
If you are getting started with React Native, you should absolutely [use this tutorial](http://www.raywenderlich.com/99473/introducing-react-native-building-apps-javascript) from Colin Eberhardt. It goes through all the steps to make a reasonably complete app.
<center>
[![](/react/img/blog/property-finder.png)](http://www.raywenderlich.com/99473/introducing-react-native-building-apps-javascript)
</center>
Colin also [blogged about his experience using React Native](http://blog.scottlogic.com/2015/03/26/react-native-retrospective.html) for a few weeks and gives his thoughts on why you would or wouldn't use it.
## The Changelog
Spencer Ahrens and I had the great pleasure to talk about React Native on [The Changelog](https://thechangelog.com/149/) podcast. It was really fun to chat for an hour, I hope that you'll enjoy listening to it. :)
<audio src="http://fdlyr.co/d/changelog/cdn.5by5.tv/audio/broadcasts/changelog/2015/changelog-149.mp3" controls="controls" style="width: 100%"></audio>
## Hacker News
Less than 24 hours after React Native was open sourced, Simarpreet Singh built an [Hacker News reader app from scratch](https://github.com/iSimar/HackerNews-React-Native). It's unbelievable how fast he was able to pull it off!
<center>
[![](/react/img/blog/hacker-news-react-native.png)](https://github.com/iSimar/HackerNews-React-Native)
</center>
## Parse + React
There's a huge ecosystem of JavaScript modules on npm and React Native was designed to work well with the ones that don't have DOM dependencies. Parse is a great example; you can `npm install parse` on your React Native project and it'll work as is. :) We still have [a](https://github.com/facebook/react-native/issues/406) [few](https://github.com/facebook/react-native/issues/370) [issues](https://github.com/facebook/react-native/issues/316) to solve; please create an issue if your favorite library doesn't work out of the box.
<center>
[![](/react/img/blog/parse-react.jpg)](http://blog.parse.com/2015/03/25/parse-and-react-shared-chemistry/)
</center>
## tcomb-form-native
Giulio Canti is the author of the [tcomb-form library](https://github.com/gcanti/tcomb-form) for React. He already [ported it to React Native](https://github.com/gcanti/tcomb-form-native) and it looks great!
<center>
[![](/react/img/blog/tcomb-react-native.png)](https://github.com/gcanti/tcomb-form-native)
</center>
## Facebook Login with React Native
One of the reason we built React Native is to be able to use all the libraries in the native ecosystem. Brent Vatne leads the way and explains [how to use Facebook Login with React Native](http://brentvatne.ca/facebook-login-with-react-native/).
## Modus Create
Jay Garcia spent a lot of time during the beta working on a NES music player with React Native. He wrote a blog post to share his experience and explains some code snippets.
<center>
[![](/react/img/blog/modus-create.gif)](http://moduscreate.com/react-native-has-landed/)
</center>
## React Native with Babel and Webpack
React Native ships with a custom packager and custom ES6 transforms instead of using what the open source community settled on such as Webpack and Babel. The main reason for this is performance we couldn't get those tools to have sub-second reload time on a large codebase.
Roman Liutikov found a way to [use Webpack and Babel to run on React Native](https://github.com/roman01la/react-native-babel)! In the future, we want to work with those projects to provide cleaner extension mechanisms.
## A Dynamic, Crazy, Native Mobile Future—Powered by JavaScript
Clay Allsopp wrote a post about [all the crazy things you could do with a JavaScript engine that renders native views](https://medium.com/@clayallsopp/a-dynamic-crazy-native-mobile-future-powered-by-javascript-70f2d56b1987). What about native embeds, seamless native browser, native search engine or even app generation...
## Random Tweet
We've spent a lot of efforts getting the onboarding as easy as possible and we're really happy that people noticed. We still have a lot of work to do on documentation, stay tuned!
<blockquote class="twitter-tweet" lang="en"><p>Wow. Getting started with React Native might have been the smoothest experience Ive ever had with a new developer product.</p>&mdash; Andreas Eldh (@eldh) <a href="https://twitter.com/eldh/status/581186172094980096">March 26, 2015</a></blockquote>

View File

@@ -0,0 +1,25 @@
---
title: "React Native v0.4"
layout: post
author: Vjeux
---
It's been three weeks since we open sourced React Native and there's been some insane amount of activity already: over 12.5k stars, 1000 commits, 500 issues, 380 pull requests, and 100 contributors, plus [35 plugins](http://react.parts/native-ios) and [1 app in the app store](http://herman.asia/building-a-flashcard-app-with-react-native)! We were expecting some buzz around the project but this is way beyond anything we imagined. Thank you!
I'd especially like to thank community members Brent Vatne and James Ide who have both already contributed meaningfully to the project and have been extremely helpful on IRC and with issues and pull requests
## Changelog
The main focus of the past few weeks has been to make React Native the best possible experience for people outside of Facebook. Here's a high level summary of what's happened since we open sourced:
* **Error messages and documentation**: We want React Native to be the absolute best developer experience for building mobile apps. We've added a lot of warnings, improved the documentation, and fixed many bugs. If you encounter anything, and I really mean anything, that is not expected or clear, please create an issue - we want to hear about it and fix it.
* **NPM modules compatibility**: There are a lot of libraries on NPM that do not depend on node/browser internals that would be really useful in React Native, such as superagent, underscore, parse, and many others. The packager is now a lot more faithful to node/browserify/webpack dependency resolution. If your favorite library doesn't work out of the box, please open up an issue.
* **Infrastructure**: We are refactoring the internals of React Native to make it easier to plug in to existing iOS codebases, as well as improve performance by removing redundant views and shadow views, supporting multiple root views and manually registering classes to reduce startup time.
* **Components**: The API for a lot of UI components and APIs, especially the ones we're not using heavily inside of Facebook, has dramatically improved thanks to many of your pull requests.
* **Tests**: We ported JavaScript tests, iOS Snapshot tests, and End to End tests to Travis CI. We have broken GitHub master a couple of times (whoops!) when syncing and we hope that with this growing suite of tests it's going to become harder and harder to do so.
* **Patent Grant**: Many of you had concerns and questions around the PATENTS file. We pushed [a new version of the grant](https://code.facebook.com/posts/1639473982937255/updating-our-open-source-patent-grant/).
* **Per commit history**: In order to synchronize from Facebook to GitHub, we used to do one giant commit every few days. We improved our tooling and now have per commit history that maintains author information (both internal and external from pull requests), and we retroactively applied this to historical diffs to provide proper attribution.
## Where are we going?
In addition to supporting pull requests, issues, and general improvements, we're also working hard on our internal React Native integrations and on React Native for Android.

View File

@@ -111,25 +111,30 @@ h1, h2, h3, h4, h5, h6 {
text-decoration: none;
}
.nav-site {
.nav-site-internal {
margin: 0 0 0 20px;
}
.nav-site-external {
float: right;
margin: 0;
}
.nav-site {
li {
margin: 0;
}
a {
padding: 0 8px;
text-transform: uppercase;
letter-spacing: 1px;
box-sizing: content-box;
padding: 0 10px;
line-height: $navHeight;
display: inline-block;
height: $navHeight;
color: $mediumTextColor;
color: #ddd;
&:hover {
color: $lightTextColor;
color: #fff;
}
&.active {
@@ -154,7 +159,8 @@ h1, h2, h3, h4, h5, h6 {
}
ul {
display: inline;
display: inline-block;
vertical-align: top;
}
li {
@@ -416,6 +422,12 @@ section.black content {
border-left: 5px solid #f7ebc6;
}
h2 > code {
font-size: inherit;
line-height: inherit;
color: #555;
background-color: rgba(0,0,0,0.04);
}
}
/**

View File

@@ -0,0 +1,30 @@
---
id: why-react-ko-KR
title: 왜 React인가?
permalink: why-react-ko-KR.html
next: displaying-data-ko-KR.html
---
React는 페이스북과 인스타그램에서 사용자 인터페이스를 구성하기 위해 만들어진 라이브러리입니다. 많은 사람들은 React를 **[MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)** 에서의 **V** 로 생각하는 경향이 있습니다.
우리는 단 하나의 문제를 해결하기 위해 React를 만들었습니다: **지속해서 데이터가 변화하는 대규모 애플리케이션을 구축하기.** 이 문제를 해결하기 위해, React는 두가지 컨셉을 도입했습니다.
## 단순함
당신의 애플리케이션이 특정 시점에 어떻게 보여야 할지를 단순히 표현하는 것만으로, 데이터가 변할 때 React는 자동으로 모든 UI 업데이트를 관리해줍니다.
## 선언적 문법
데이터가 변할 때 React는 "새로 고침" 버튼을 누르듯이 작동하며, 데이터의 바뀐 부분만을 업데이트할 수 있습니다.
## 구성적인 컴포넌트를 만드세요
React는 재사용 가능한 컴포넌트들을 만드는 데에 도움이 됩니다. 사실, React를 사용하면 *단지* 컴포넌트를 만드는 일만 하게 됩니다. 컴포넌트들은 잘 캡슐화되어 되어 있기 때문에, 컴포넌트들은 코드의 재사용성을 높이고, 테스트를 쉽게 해 주며, 관심 분리의 원칙(separation of concerns)을 지키게 해 줍니다.
## 5분만 투자하세요
React는 많은 관습적인 사고에 도전하며, 첫눈에 볼 때는 이상한 아이디어들의 모음이라고 생각할 수도 있습니다. 이 가이드를 읽기 위해 [5분만 투자하세요](http://37signals.com/svn/posts/3124-give-it-five-minutes); 그 이상한 아이디어들은 페이스북과 인스타그램 안팎의 수천 개의 컴포넌트들을 만드는 데에 사용되었기 때문입니다.
## 더 알아보기
[이 블로그 포스트](http://facebook.github.io/react/blog/2013/06/05/why-react.html)에서 React를 만든 우리의 동기에 대해 알아볼 수 있습니다.

View File

@@ -8,11 +8,11 @@ React is a JavaScript library for creating user interfaces by Facebook and Insta
We built React to solve one problem: **building large applications with data that changes over time**. To do this, React uses two main ideas.
### Simple
## Simple
Simply express how your app should look at any given point in time, and React will automatically manage all UI updates when your underlying data changes.
### Declarative
## Declarative
When the data changes, React conceptually hits the "refresh" button, and knows to only update the changed parts.

View File

@@ -0,0 +1,126 @@
---
id: displaying-data-ko-KR
title: 데이터를 표시하기
permalink: displaying-data-ko-KR.html
prev: why-react-ko-KR.html
next: jsx-in-depth-ko-KR.html
---
UI를 가지고 할 수 있는 가장 기초적인 것은 데이터를 표시하는 것입니다. React는 데이터를 표시하고 데이터가 변할 때마다 인터페이스를 최신의 상태로 자동으로 유지하기 쉽게 해 줍니다.
## 시작하기
정말 간단한 예제를 보도록 하죠. 다음과 같은 코드의 `hello-react.html` 파일을 만듭시다.
```html
<!DOCTYPE html>
<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>
</head>
<body>
<div id="example"></div>
<script type="text/jsx">
// ** 코드는 여기에 작성하면 됩니다! **
</script>
</body>
</html>
```
문서의 나머지에서, 코드가 위와 같은 HTML 템플릿에 들어갔다고 가정하고 JavaScript 코드에만 집중할 것입니다. 위의 주석 부분을 다음과 같은 JavaScript 코드로 바꿔 보세요:
```javascript
var HelloWorld = React.createClass({
render: function() {
return (
<p>
안녕, <input type="text" placeholder="이름을 여기에 작성하세요" />!
지금 시간은 {this.props.date.toTimeString()} 입니다.
</p>
);
}
});
setInterval(function() {
React.render(
<HelloWorld date={new Date()} />,
document.getElementById('example')
);
}, 500);
```
## 반응 적(Reactive) 업데이트
`hello-react.html` 파일을 웹 브라우저에서 열어 당신의 이름을 텍스트 필드에 써 보세요. React는 단지 시간을 표시하는 부분만을 바꿉니다 — 텍스트 필드 안에 입력한 것은 그대로 남아 있구요, 당신이 이 동작을 관리하는 그 어떤 코드도 쓰지 않았음에도 불구하고 말이죠. React는 그걸 올바른 방법으로 알아서 해줍니다.
우리가 이걸 할 수 있었던 건, React는 필요한 경우에만 DOM을 조작하기 때문입니다. **React는 빠른 React 내부의 DOM 모형을 이용하여 변경된 부분을 측정하고, 가장 효율적인 DOM 조작 방법을 계산해 줍니다.**
이 컴포넌트에 대한 입력은 `props` 라고 불립니다 — "properties" 를 줄인 것이죠. 그들은 JSX 문법에서는 어트리뷰트로서 전달됩니다. 당신은 `props` 를 컴포넌트 안에서 불변의(immutable) 엘리먼트로서 생각해야 하고, `this.props` 를 덮어씌우려고 해서는 안됩니다.
## 컴포넌트들은 함수와 같습니다
React 컴포넌트들은 매우 단순합니다. 당신은 그것들을 `props``state` (이것들은 나중에 언급할 것입니다) 를 받고 HTML을 렌더링하는 단순한 함수들로 생각해도 됩니다. 그것들은 너무 단순하기 때문에, 그것들의 작동을 이해하는 것 또한 쉽게 만듭니다.
> 주의:
>
> **한가지 제약이 있습니다**: React 컴포넌트들은 단 하나의 루트 노드(root node)만을 렌더할 수 있습니다. 만약 여러개의 노드들을 리턴하고 싶다면, 그것들은 단 하나의 루트 노드로 싸여져 있어야만 합니다.
## JSX 문법
우리는 컴포넌트를 사용하는 것이 "템플릿"과 "디스플레이 로직(display logic)"을 이용하는 것보다 관심을 분리(separate concerns)하는 데에 올바른 방법이라고 강하게 믿고 있습니다. 우리는 마크업과 그것을 만들어내는 코드는 친밀하게 함께 결합되어있다고 생각합니다. 또한, 디스플레이 로직은 종종 매우 복잡하고, 그것을 템플릿 언어를 이용해 표현하는 것은 점점 사용하기 어렵게 됩니다.
우리는 이 문제를 해결하는 최고의 해결책은, UI를 만드는 진짜 프로그래밍 언어의 표현력을 모두 사용할 수 있는 JavaScript 코드로부터 HTML과 컴포넌트 트리들을 생성하는 것임을 발견했습니다.
이것을 더 쉽게 하기 위해서, 우리는 매우 간단하고, **선택적인** HTML과 비슷한 문법을 추가하여 이 React 트리 노드들을 만들 수 있게 했습니다.
**JSX는 당신으로 하여금 HTML 문법을 이용해 JavaScript 객체를 만들게 해줍니다.** React를 이용해 순수한 JavaScript 문법으로 링크를 만드려고 한다면, 코드는 다음과 같습니다:
`React.createElement('a', {href: 'http://facebook.github.io/react/'}, '안녕하세요!')`
JSX를 이용하면:
`<a href="http://facebook.github.io/react/">안녕하세요!</a>`
우리는 이것이 React 앱들을 만들기 쉽게 하고, 디자이너들이 이 문법을 더 선호하는 것을 발견했습니다, 하지만 모든 사람은 그들만의 선호하는 워크플로우가 있기 마련이므로, **JSX는 React를 사용하기 위해 필수적이지는 않습니다.**
JSX는 매우 작은 언어입니다. 그것을 배우고 싶다면, [JSX 깊게 살펴보기](/react/docs/jsx-in-depth-ko-KR.html). 를 살펴 보시기 바랍니다. 또는, [우리의 온라인 JSX 컴파일러](/react/jsx-compiler.html)를 통해 문법이 변환되는 것을 살펴 보시기 바랍니다.
JSX는 HTML과 비슷하지만, 완전히 똑같지는 않습니다. [JSX의 실수하기 쉬운 부분들](/react/docs/jsx-gotchas-ko-KR.html)에 중요한 차이점들에 대해 설명되어 있습니다.
JSX를 사용하기 시작하기 위한 가장 쉬운 방법은 브라우저에서 작동하는 `JSXTransformer`를 사용하는 것입니다. 우리는 이것을 프로덕션에서는 사용하지 않기를 강하게 권장하는 바입니다. 당신은 우리의 커맨드 라인 [react-tools](http://npmjs.org/package/react-tools) 패키지를 이용하여 미리 컴파일(precompile)해 사용할 수 있습니다.
## JSX 없이 React 사용하기
JSX는 완전히 선택적입니다. 당신은 React와 JSX를 함께 사용하지 않아도 상관없습니다. 그냥 JavaScript에서 React 엘리먼트를 `React.createElement`로 만들 수 있습니다. 여기에 태그 이름이나 컴포넌트, 속성 객체, 자식 엘리먼트들을 전달하면 됩니다.
```javascript
var child1 = React.createElement('li', null, 'First Text Content');
var child2 = React.createElement('li', null, 'Second Text Content');
var root = React.createElement('ul', { className: 'my-list' }, child1, child2);
React.render(root, document.getElementById('example'));
```
편의를 위하여, 당신은 팩토리 함수 헬퍼들을 이용해 커스텀 컴포넌트로부터 엘리먼트들을 만들 수 있습니다.
```javascript
var Factory = React.createFactory(ComponentClass);
...
var root = Factory({ custom: 'prop' });
React.render(root, document.getElementById('example'));
```
React는 이미 일반적인 HTML 태그에 대한 빌트인 팩토리를 가지고 있습니다.
```javascript
var root = React.DOM.ul({ className: 'my-list' },
React.DOM.li(null, '텍스트')
);
```

View File

@@ -106,7 +106,7 @@ JSX is completely optional; you don't have to use JSX with React. You can create
var child1 = React.createElement('li', null, 'First Text Content');
var child2 = React.createElement('li', null, 'Second Text Content');
var root = React.createElement('ul', { className: 'my-list' }, child1, child2);
React.render(root, document.body);
React.render(root, document.getElementById('example'));
```
As a convenience you can create short-hand factory functions to create elements from custom components.
@@ -115,7 +115,7 @@ As a convenience you can create short-hand factory functions to create elements
var Factory = React.createFactory(ComponentClass);
...
var root = Factory({ custom: 'prop' });
React.render(root, document.body);
React.render(root, document.getElementById('example'));
```
React already has built-in factories for common HTML tags:

View File

@@ -104,7 +104,7 @@ JSX 类似于 HTML但不是完全一样。参考 [JSX 陷阱](/react/docs/jsx
```javascript
var child = React.createElement('li', null, 'Text Content');
var root = React.createElement('ul', { className: 'my-list' }, child);
React.render(root, document.body);
React.render(root, document.getElementById('example'));
```
方便起见,你可以创建基于自定义组件的速记工厂方法。
@@ -113,7 +113,7 @@ React.render(root, document.body);
var Factory = React.createFactory(ComponentClass);
...
var root = Factory({ custom: 'prop' });
React.render(root, document.body);
React.render(root, document.getElementById('example'));
```
React 已经为 HTML 标签提供内置工厂方法。

View File

@@ -0,0 +1,210 @@
---
id: jsx-in-depth-ko-KR
title: JSX 깊이보기
permalink: jsx-in-depth-ko-KR.html
prev: displaying-data-ko-KR.html
next: jsx-spread-ko-KR.html
---
[JSX](http://facebook.github.io/jsx/)는 XML과 비슷한 JavaScript문법 확장입니다. React에서 변환되는 간단한 JSX 구문을 사용하실 수 있습니다.
## 왜 JSX인가?
React를 위해 꼭 JSX를 사용할 필요는 없고, 그냥 일반 JS를 사용할 수도 있습니만 JSX를 사용하기를 추천합니다. 왜냐하면, 어트리뷰트를 가진 트리 구조로 정의할 수 있는 간결하고 익숙한 문법이기 때문입니다.
이것은 디자이너 같은 케쥬얼 개발자에게 더 익숙합니다.
XML에는 여닫는 태그의 장점이 있습니다. 태그는 큰 트리일 때 함수 호출이나 객체 리터럴보다 읽기 쉬워 집니다.
JSX는 JavaScript의 시맨틱을 변경하지 않습니다.
## HTML 태그 vs. React 컴포넌트
React는 렌더 HTML 태그(문자열)이나 React 컴포넌트(클래스)일 수 있습니다.
HTML 태그를 렌더하려면, 그냥 JSX에 소문자 태그를 사용하세요.
```javascript
var myDivElement = <div className="foo" />;
React.render(myDivElement, document.getElementById('example'));
```
React 컴포넌트를 렌더하려면, 대문자로 시작하는 로컬 변수를 만드세요.
```javascript
var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />;
React.render(myElement, document.getElementById('example'));
```
React JSX는 대소문자를 로컬 컴포넌트 클래스와 HTML 태그를 구별하는 컨벤션으로 사용합니다.
> 주의:
>
> JSX가 JavaScript기 때문에, `class`, `for`같은 식별자는 XML 어트리뷰트 이름으로
> 권장하지 않습니다. 대신, React DOM 컴포넌트는 각각 `className`, `htmlFor`같은
> DOM 프로퍼티 이름을 기대합니다.
<a name="the-transform"></a>
## 변환
React JSX는 XML같은 문법에서 네이티브 JavaScript로 변환됩니다. XML 엘리먼트, 어트리뷰트, 자식은 `React.createElement`에 넘겨지는 인자로 변환됩니다.
```javascript
var Nav;
// 입력 (JSX):
var app = <Nav color="blue" />;
// 출력 (JS):
var app = React.createElement(Nav, {color:"blue"});
```
`<Nav />`를 사용하려면, `Nav`변수는 스코프에 있어야 합니다.
JSX에서는 XML 구문으로 자식을 지정할 수도 있습니다.
```javascript
var Nav, Profile;
// 입력 (JSX):
var app = <Nav color="blue"><Profile>click</Profile></Nav>;
// 출력 (JS):
var app = React.createElement(
Nav,
{color:"blue"},
React.createElement(Profile, null, "click")
);
```
클래스에 [displayName](/react/docs/component-specs-ko-KR.html#displayName)이 정의되어 있지 않으면 JSX는 변수명을 displayName으로 간주할 것입니다:
```javascript
// 입력 (JSX):
var Nav = React.createClass({ });
// 출력 (JS):
var Nav = React.createClass({displayName: "Nav", });
```
[JSX 컴파일러](/react/jsx-compiler.html)를 보면 JSX에서 어떻게 네이티브 JavaScript로 변환(desugars)하는지 볼 수 있고, [HTML-JSX 변환기](/react/html-jsx.html)는 이미 있는 HTML을 JSX로 변환해 줍니다.
JSX를 사용 하시려면, [시작하기](/react/docs/getting-started-ko-KR.html) 가이드에서 어떻게 컴파일을 하기 위해 설정하는지 보실 수 있습니다.
> 주의:
>
> JSX 표현식은 언제나 ReactElement로 평가됩니다. 실제 구현의 세부사항은 많이
> 다를 수 있습니다. 최적화 모드는ReactElement를 `React.createElement`에서 검증
> 코드를 우회하는 객체 리터럴로 ReactElement를 인라인으로 만들 수 있습니다.
## 네임스페이스를 사용한 컴포넌트
폼같은 자식을 많이 가지는 컴포넌트를 만든다면, 많은 변수 선언을 하게 될 것입니다.
```javascript
// 변수 선언의 어색한 블록
var Form = MyFormComponent;
var FormRow = Form.Row;
var FormLabel = Form.Label;
var FormInput = Form.Input;
var App = (
<Form>
<FormRow>
<FormLabel />
<FormInput />
</FormRow>
</Form>
);
```
더 간단하고 쉽게 *네임스페이스를 사용한 컴포넌트*를 사용해서, 다른 컴포넌트를 어트리뷰트로 가지는 하나의 컴포넌트만 쓸 수 있습니다.
```javascript
var Form = MyFormComponent;
var App = (
<Form>
<Form.Row>
<Form.Label />
<Form.Input />
</Form.Row>
</Form>
);
```
이렇게 하려면, *"sub-components"*를 메인 컴포넌트의 어트리뷰트로 만들 필요가 있습니다.
```javascript
var MyFormComponent = React.createClass({ ... });
MyFormComponent.Row = React.createClass({ ... });
MyFormComponent.Label = React.createClass({ ... });
MyFormComponent.Input = React.createClass({ ... });
```
코드를 컴파일할 때 JSX는 이것을 제대로 처리해 줍니다.
```javascript
var App = (
React.createElement(Form, null,
React.createElement(Form.Row, null,
React.createElement(Form.Label, null),
React.createElement(Form.Input, null)
)
)
);
```
> 주의:
>
> 이 기능은 [v0.11](http://facebook.github.io/react/blog/2014/07/17/react-v0.11.html#jsx) 이상에만 있습니다.
## JavaScript 표현식
### 어트리뷰트 표현식
JavaScript 표현식을 어트리뷰트 값으로 사용하려면, 표현식을 쌍따옴표(`""`)대신 중괄호(`{}`)로 감싸야 합니다.
```javascript
// 입력 (JSX):
var person = <Person name={window.isLoggedIn ? window.name : ''} />;
// 출력 (JS):
var person = React.createElement(
Person,
{name: window.isLoggedIn ? window.name : ''}
);
```
### 자식 표현식
비슷하게, JavaScript 표현식을 자식을 표현하는 데 사용할 수 있습니다.
```javascript
// 입력 (JSX):
var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>;
// 출력 (JS):
var content = React.createElement(
Container,
null,
window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login)
);
```
### 주석
JSX에 주석을 넣기는 쉽습니다. 그냥 JS 표현식과 같습니다. 그냥 태그의 자식 섹션에서만 조심하시면 됩니다. 이럴 땐 주석 주변에 `{}`를 감싸야 합니다.
```javascript
var content = (
<Nav>
{/* 자식 주석, {}로 감싼다 */}
<Person
/* 여러
주석 */
name={window.isLoggedIn ? window.name : ''} // 줄 끝부분 주석
/>
</Nav>
);
```
> 주의:
>
> JSX 는 HTML과 비슷하지만 완전히 같지는 않습니다. 중요한 차이점을 보시려면 [JSX gotchas](/react/docs/jsx-gotchas-ko-KR.html)를 보세요.

View File

@@ -26,7 +26,7 @@ To render a HTML tag, just use lower-case tag names in JSX:
```javascript
var myDivElement = <div className="foo" />;
React.render(myDivElement, document.body);
React.render(myDivElement, document.getElementById('example'));
```
To render a React Component, just create a local variable that starts with an upper-case letter:
@@ -34,7 +34,7 @@ To render a React Component, just create a local variable that starts with an up
```javascript
var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />;
React.render(myElement, document.body);
React.render(myElement, document.getElementById('example'));
```
React's JSX uses the upper vs. lower case convention to distinguish between local component classes and HTML tags.
@@ -73,7 +73,7 @@ var app = React.createElement(
);
```
JSX will infer the class's [displayName](/react/docs/component-specs.html#displayName) from the variable assignment when the displayName is undefined:
JSX will infer the class's [displayName](/react/docs/component-specs.html#displayname) from the variable assignment when the displayName is undefined:
```javascript
// Input (JSX):
@@ -92,7 +92,7 @@ If you want to use JSX, the [Getting Started](/react/docs/getting-started.html)
> Note:
>
> The JSX expression always evaluates to a ReactElement. The actual
> implementation details may vary. An optimized mode could inline the
> implementation details may vary. An optimized mode could inline the
> ReactElement as an object literal to bypass the validation code in
> `React.createElement`.
@@ -146,9 +146,9 @@ JSX will handle this properly when compiling your code.
```javascript
var App = (
React.createElement(Form, null,
React.createElement(Form.Row, null,
React.createElement(Form.Label, null),
React.createElement(Form, null,
React.createElement(Form.Row, null,
React.createElement(Form.Label, null),
React.createElement(Form.Input, null)
)
)
@@ -210,5 +210,5 @@ var content = (
```
> NOTE:
>
>
> JSX is similar to HTML, but not exactly the same. See [JSX gotchas](/react/docs/jsx-gotchas.html) for some key differences.

View File

@@ -28,7 +28,7 @@ React 可以渲染 HTML 标签 (strings) 或 React 组件 (classes)。
```javascript
var myDivElement = <div className="foo" />;
React.render(myDivElement, document.body);
React.render(myDivElement, document.getElementById('example'));
```
要渲染 React 组件,只需创建一个大写字母开头的本地变量。
@@ -36,7 +36,7 @@ React.render(myDivElement, document.body);
```javascript
var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />;
React.render(myElement, document.body);
React.render(myElement, document.getElementById('example'));
```
React 的 JSX 里约定分别使用首字母大、小写来区分本地组件的类和 HTML 标签。

View File

@@ -0,0 +1,56 @@
---
id: jsx-spread-ko-KR
title: JSX 스프레드 어트리뷰트
permalink: jsx-spread-ko-KR.html
prev: jsx-in-depth-ko-KR.html
next: jsx-gotchas-ko-KR.html
---
미리 컴포넌트에 넣을 모든 프로퍼티를 알게 된다면, JSX를 사용하기 쉬워집니다.
```javascript
var component = <Component foo={x} bar={y} />;
```
## Props의 변경은 나빠요.[^1]
하지만 어떤 프로퍼티를 설정하고 싶은지 모른다면, 객체 레이어에 넣고 싶어질 수도 있습니다.
```javascript
var component = <Component />;
component.props.foo = x; // 나쁨
component.props.bar = y; // 역시 나쁨
```
이것은 안티 패턴입니다. 왜냐하면 한참 뒤까지 정확한 propTypes을 체크할 수 없다는 뜻이기 때문입니다. 이것은 propTypes 에러는 알기 힘든 스택 트레이스로 끝난다는 의미입니다.
이 시점에서 props는 불변성인 것을 고려해야 합니다. props 객체를 변경하는 것은 다른 곳에서 예기치 못한 결과가 생길 수 있기 때문에 이상적으로는 이 시점에서 frozen 객체가 되어야 합니다.
## 스프레드 어트리뷰트
이제 JSX의 새로운 기능인 스프레드 어트리뷰트를 사용하실 수 있습니다.
```javascript
var props = {};
props.foo = x;
props.bar = y;
var component = <Component {...props} />;
```
전달한 객체의 프로퍼티가 컴포넌트의 props에 복사됩니다.
이렇게 여러 번 사용하거나 다른 어트리뷰트와 조합해서 사용할 수 있습니다. 명세의 순서는 중요합니다. 나중의 어트리뷰트가 이전 것보다 우선되기 때문입니다.
```javascript
var props = { foo: 'default' };
var component = <Component {...props} foo={'override'} />;
console.log(component.props.foo); // 'override'
```
## 이상한 `...` 표기법은 무엇인가요?
`...` 연산자(스프레드 연산자)는 이미 [ES6의 배열](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator)에서 지원합니다. [객체 rest와 스프레드 프로퍼티](https://github.com/sebmarkbage/ecmascript-rest-spread)에 대한 ES7의 제안도 있습니다. JSX의 구문을 더 깔끔하게 하기 위해 지원되고 개발중인 표준을 활용하고 있습니다.
[^1]: 아무래도 좋지만, 이 제목의 원문 "Mutating Props is Bad, mkay"는 사우스 파크에
나온 대사 "[Drug is bad, mkay](https://www.youtube.com/watch?v=Uh7l8dx-h8M)"의
패러디입니다.

View File

@@ -0,0 +1,68 @@
---
id: jsx-gotchas-ko-KR
title: JSX Gotchas
permalink: jsx-gotchas-ko-KR.html
prev: jsx-spread-ko-KR.html
next: interactivity-and-dynamic-uis-ko-KR.html
---
JSX는 HTML처럼 보이지만, 작업하다 보면 마주치게 될 몇 가지 중요한 차이점이 있습니다.
> 주의:
>
> 인라인 `style` 어트리뷰트 같은 DOM과의 차이점은 [여기](/react/tips/dangerously-set-inner-html-ko-KR.html)를 보세요.
## HTML 엔티티
JSX의 리터럴 텍스트에 HTML 엔티티를 넣을 수 있습니다.
```javascript
<div>First &middot; Second</div>
```
동적 콘텐츠 안에 HTML 엔티티를 표시하려 할 때, React에서는 XSS 공격을 광범위하게 막기 위해서 기본적으로 모든 표시하는 문자열을 이스케이프 하기 때문에 더블 이스케이프 문제에 부딪히게 됩니다.
```javascript
// 나쁨: "First &middot; Second"를 표시
<div>{'First &middot; Second'}</div>
```
이 이슈를 피해 갈 방법은 여럿 있지만, 가장 쉬운 방법은 유니코드 문자를 JavaScript에 직접 쓰는 것입니다. 브라우저가 올바르게 표시하도록 파일이 UTF-8으로 저장되어 있고 올바른 UTF-8 지시자를 사용하고 있는지 확인해야 합니다.
```javascript
<div>{'First · Second'}</div>
```
더 안전한 대안으로 [엔티티에 대응하는 유니코드 숫자](http://www.fileformat.info/info/unicode/char/b7/index.htm)를 찾아 JavaScript 문자열 안에서 사용하는 방법도 있습니다.
```javascript
<div>{'First \u00b7 Second'}</div>
<div>{'First ' + String.fromCharCode(183) + ' Second'}</div>
```
문자열과 JSX 엘리먼트를 혼합한 배열을 사용할 수도 있습니다.
```javascript
<div>{['First ', <span>&middot;</span>, ' Second']}</div>
```
최후의 수단으로, 항상 [생 HTML을 삽입](/react/docs/dom-differences-ko-KR.html)할 수 있습니다.
```javascript
<div dangerouslySetInnerHTML={{'{{'}}__html: 'First &middot; Second'}} />
```
## 커스텀 HTML 어트리뷰트
프로퍼티를 HTML 사양에는 없는 네이티브 HTML 엘리먼트에 넘기면, React는 그 프로퍼티를 렌더하지 않습니다. 커스텀 어트리뷰트를 사용하고 싶다면, 접두사로 `data-`를 붙이셔야 합니다.
```javascript
<div data-custom-attribute="foo" />
```
`aria-`로 시작하는 [Web 접근성](http://www.w3.org/WAI/intro/aria) 어트리뷰트는 제대로 렌더될 것입니다.
```javascript
<div aria-hidden={true} />
```

View File

@@ -46,7 +46,7 @@ You can use mixed arrays with strings and JSX elements.
<div>{['First ', <span>&middot;</span>, ' Second']}</div>
```
As a last resort, you always have the ability to [insert raw HTML](/react/docs/dom-differences.html).
As a last resort, you always have the ability to [insert raw HTML](/react/tips/dangerously-set-inner-html.html).
```javascript
<div dangerouslySetInnerHTML={{'{{'}}__html: 'First &middot; Second'}} />

View File

@@ -0,0 +1,85 @@
---
id: interactivity-and-dynamic-uis-ko-KR
title: 상호 작용 및 동적 UI
permalink: interactivity-and-dynamic-uis-ko-KR.html
prev: jsx-gotchas-ko-KR.html
next: multiple-components-ko-KR.html
---
이미 React에서 [어떻게 데이터를 표시](/react/docs/displaying-data-ko-KR.html)하는지를 배웠습니다. 이제 UI와의 상호작용을 어떻게 만드는지 살펴보죠.
## 간단한 예제
```javascript
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false};
},
handleClick: function(event) {
this.setState({liked: !this.state.liked});
},
render: function() {
var text = this.state.liked ? 'like' : 'haven\'t liked';
return (
<p onClick={this.handleClick}>
You {text} this. Click to toggle.
</p>
);
}
});
React.render(
<LikeButton />,
document.getElementById('example')
);
```
## 이벤트 핸들링과 통합적인(Synthetic) 이벤트
React에서의 이벤트 핸들러는 HTML에서 그러던 것처럼 간단히 카멜케이스 프로퍼티(camelCased prop)로 넘기면 됩니다. React의 모든 이벤트는 통합적인 이벤트 시스템의 구현으로 IE8 이상에서는 같은 행동이 보장됩니다. 즉, React는 사양에 따라 어떻게 이벤트를 일으키고(bubble) 잡는지 알고 있고, 당신이 사용하는 브라우저와 관계없이 이벤트 핸들러에 전달되는 이벤트는 [W3C 사양](http://www.w3.org/TR/DOM-Level-3-Events/)과 같도록 보장됩니다.
## 기본 구현: 오토바인딩과 이벤트 델리게이션
<a name="under-the-hood-autobinding-and-event-delegation"></a>
코드를 고성능으로 유지하고 이해하기 쉽게 하기 위해, React는 보이지 않는 곳에서 몇 가지 일을 수행합니다.
**오토바인딩:** JavaScript에서 콜백을 만들 때, 보통은 `this`의 값이 정확하도록 명시적으로 메소드를 인스턴스에 바인드해야 합니다. React에서는 모든 메소드가 자동으로 React의 컴포넌트 인스턴스에 바인드됩니다. React가 바인드 메소드를 캐시하기 때문에 매우 CPU와 메모리에 효율적입니다. 타이핑해야 할 것도 줄어들죠!
**이벤트 델리게이션:** React는 실제로는 노드자신에게 이벤트 핸들러를 붙이지 않습니다. React가 시작되면 React는 탑 레벨의 단일 이벤트 리스너로 모든 이벤트를 리스닝하기 시작합니다. 컴포넌트가 마운트되거나 언마운트 될 때, 이벤트 핸들러는 그냥 내부 매핑에서 넣거나 뺄 뿐입니다. 이벤트가 발생하면, React는 이 매핑을 사용해서 어떻게 디스패치할 지를 알게 됩니다. 매핑에 이벤트 핸들러가 남아있지 않으면, React의 이벤트 핸들러는 그냥 아무것도 하지 않습니다. 왜 이 방식이 빠른지 더 알고 싶으시면, [David Walsh의 멋진 블로그 글](http://davidwalsh.name/event-delegate)을 읽어 보세요.
## 컴포넌트는 그냥 state 머신일 뿐
React는 UI를 간단한 state 머신이라 생각합니다. UI를 다양한 state와 그 state의 렌더링으로 생각함으로써 UI를 일관성 있게 관리하기 쉬워집니다.
React에서는, 간단히 컴포넌트의 state를 업데이트하고, 이 새로운 state의 UI를 렌더링합니다. React는 DOM의 변경을 가장 효율적인 방법으로 관리해줍니다.
## state의 동작 원리
React에게 데이터의 변경을 알리는 일반적인 방법은 `setState(data, callback)`을 호출하는 것입니다. 이 메소드는 `this.state``data`를 머지하고 컴포넌트를 다시 렌더링 합니다. 컴포넌트의 재-렌더링이 끝나면, 생략가능한 `callback`이 호출됩니다. 대부분의 경우 React가 UI를 최신상태로 유지해주기 때문에 `callback`을 사용할 필요가 없습니다.
## 어떤 컴포넌트가 state를 가져야 할까요?
대부분의 컴포넌트는 `props`로부터 데이터를 받아 렌더할 뿐입니다만, 가끔 유저 인풋, 서버 요청, 시간의 경과에 반응해야 할 필요가 있습니다. 이럴 때 state를 사용합니다.
**가능한 한 컴포넌트가 상태를 가지지 않도록(stateless) 하세요.** 이렇게 함으로써 가장 논리적인 장소로 state를 격리하게 되고 쉽게 애플리케이션을 추론할 수 있도록 중복을 최소화할 수 있습니다.
일반적인 패턴은 데이터만 렌더하는 여러 상태를 가지지 않은 컴포넌트를 만들고, 그 위에 상태기반(stateful) 컴포넌트를 만들어 계층 안의 자식 컴포넌트에게 `props`를 통해 state를 전달하는 것입니다. state를 가지지 않은 컴포넌트가 선언적인 방법으로 데이터를 렌더링 하는 동안, 상태기반 컴포넌트는 모든 상호작용 로직을 캡슐화합니다.
## state를 어떻게 *써야* 할까요?
**state는 컴포넌트의 이벤트 핸들러에 의해 UI 업데이트를 트리거할때 변경될 가능성이 있어, 그때 사용할 데이터를 가져야 합니다.** 실제 앱에서는 이 데이터는 매우 작고 JSON 직렬화 가능한 경향이 있습니다. 상태기반 컴포넌트를 만들때, 가능한 작게 state를 서술하고 `this.state`에만 저장하도록 해보세요. 그냥 `render()` 안에서 이 state를 기반으로 다른 모든 정보를 계산합니다. 이 방식으로 애플리케이션을 작성하고 생각하면 가장 최적의 애플리케이션으로 발전해가는 경향이 있다는 것을 발견하게 될 것입니다. 꼭 필요하지 않은 값이나 계산된 값을 state에 추가하는 것은 render가 그것을 계산하는 대신에 명시적으로 그것들을 맞춰줘야 하는 것을 의미하기 때문이죠.
## state를 어떻게 *쓰지 말아야* 할까요?
`this.state`는 UI의 state를 표현할 최소한의 데이터만을 가져야 합니다. 그래서 이런 것들을 가지지 않게끔 해야 합니다.
* **계산된 데이터:** state에 따라 값을 미리 계산하는 것에 대해 염려하지 마세요. 계산은 모두 `render()`에서 하는 것이 UI의 일관성을 유지하기 쉽습니다. 예를 들어, state에서 list items 배열을 가지고 있고 문자열으로 카운트를 렌더링 할 경우, state에 저장하기보다는 그냥 `render()` 메소드안에서 `this.state.listItems.length + ' list items'`를 렌더하세요.
* **React 컴포넌트:** 가지고 있는 props와 state로 `render()`안에서 만드세요.
* **props에서 복사한 데이터:** 가능한 한 원래의 소스로 props를 사용하도록 해보세요. props를 state에 저장하는 단 하나의 올바른 사용법은 이전 값을 알고 싶을 때입니다. props는 시간이 지나면 변경될 수도 있기 때문이죠.

View File

@@ -0,0 +1,190 @@
---
id: multiple-components-ko-KR
title: 복합 컴포넌트
permalink: multiple-components-ko-KR.html
prev: interactivity-and-dynamic-uis-ko-KR.html
next: reusable-components-ko-KR.html
---
지금까지, 단일 컴포넌트에서 데이터를 표시하고 유저 입력을 다루는 것을 살펴보았습니다. 다음엔 React의 최고의 기능 중 하나인 조합가능성(composability)을 살펴봅시다.
## 동기: 관심의 분리
명확히 정의된 인터페이스와 다른 컴포넌트를 재사용해 모듈러 컴포넌트를 구축하면, 함수와 클래스를 이용했을 때 얻을 수 있는 이점 대부분을 얻을 수 있습니다. 특히 앱에서 *다른 관심을 분리*할 수 있습니다.아무리 간단히 새 컴포넌트를 만들었다고 해도 말이죠. 당신의 애플리케이션에서 쓸 커스텀 컴포넌트 라이브러리를 만들어서, 당신의 도메인에 최적화된 방법으로 UI를 표현할 수 있게 됩니다.
## 조합(Composition) 예제
간단히 페이스북 그래프 API를 사용해 프로필 사진과 유저이름을 보여주는 아바타 컴포넌트를 만든다고 합시다.
```javascript
var Avatar = React.createClass({
render: function() {
return (
<div>
<ProfilePic username={this.props.username} />
<ProfileLink username={this.props.username} />
</div>
);
}
});
var ProfilePic = React.createClass({
render: function() {
return (
<img src={'http://graph.facebook.com/' + this.props.username + '/picture'} />
);
}
});
var ProfileLink = React.createClass({
render: function() {
return (
<a href={'http://www.facebook.com/' + this.props.username}>
{this.props.username}
</a>
);
}
});
React.render(
<Avatar username="pwh" />,
document.getElementById('example')
);
```
## 소유권(Ownership)
위의 예제에서, `Avatar` 인스턴스는 `ProfilePic``ProfileLink`인스턴스를 *가지고* 있습니다. React에서 **소유자는 다른 컴포넌트의 `props`를 설정하는 컴포넌트입니다**. 더 정식으로 말하면, `X` 컴포넌트가 `Y` 컴포넌트의 `render()` 메소드 안에서 만들어졌다면, `Y``X`*소유하고* 있다고 합니다. 앞에서 설명한 바와 같이, 컴포넌트는 자신의 `props`를 변경할 수 없습니다. `props`는 언제나 소유자가 설정한 것과 일치합니다. 이와 같은 중요한 성질은 UI가 일관성 있도록 해줍니다.
소유(owner-ownee)관계와 부모·자식 관계를 구별하는 것은 중요합니다. 부모·자식 관계가 DOM에서부터 쓰던 익숙하고 이미 알고있던 단순한 것인 한편, 소유관계는 React 고유의 것입니다. 위의 예제에서, `Avatar``div`, `ProfilePic`, `ProfileLink`인스턴스를 소유하고, `div``ProfilePic``ProfileLink`인스턴스의 (소유자가 아닌) **부모**입니다.
## 자식
React 컴포넌트 인스턴스를 만들 때, 추가적인 React 컴포넌트나 JavaScript 표현식을 시작과 끝 태그 사이에 넣을 수 있습니다. 이렇게 말이죠.
```javascript
<Parent><Child /></Parent>
```
`Parent``this.props.children`라는 특수 prop으로 자식들을 읽을 수 있습니다. **`this.props.children` 는 불투명한 데이터 구조이며,** [React.Children 유틸리티](/react/docs/top-level-api-ko-KR.html#react.children)를 사용해 자식들을 관리합니다.
### 자식 Reconciliation (비교조정)
**Reconciliation은 React가 DOM을 각각 새로운 렌더 패스에 업데이트하는 과정입니다.** 일반적으로, 자식은 렌더하는 순서에 따라 비교조정됩니다. 예를 들어, 각각의 마크업을 생성하는 두 개의 렌더 패스가 있다고 해봅시다.
```html
// Render Pass 1
<Card>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</Card>
// Render Pass 2
<Card>
<p>Paragraph 2</p>
</Card>
```
직관적으로 보면, `<p>Paragraph 1</p>`가 없어졌습니다만 그러는 대신에, React는 첫 번째 자식의 텍스트를 비교조정하고 마지막 자식을 파괴하도록 DOM을 비교조정할 것입니다. React는 자식들의 *순서*에 따라 비교조정합니다.
### 상태기반(Stateful) 자식
대부분의 컴포넌트에서는, 이것은 큰 문제가 아닙니다. 하지만 렌더 패스 간에 `this.state`를 유지하는 상태기반의 컴포넌트에서는 매우 문제가 될 수 있습니다.
대부분의 경우, 이 문제는 엘리먼트를 파괴하지 않고 숨김으로써 피해갈 수 있습니다.
```html
// Render Pass 1
<Card>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</Card>
// Render Pass 2
<Card>
<p style={{'{{'}}display: 'none'}}>Paragraph 1</p>
<p>Paragraph 2</p>
</Card>
```
<a name="dynamic-children"></a>
### 동적 자식
자식들이 섞이거나(검색의 결과같은 경우) 새로운 컴포넌트가 목록의 앞에 추가(스트림같은 경우)된다면 상황은 점점 더 까다로워집니다. 이런 때에의 동일성과 각 자식의 상태는 반드시 렌더 패스 간에 유지돼야 합니다. 각 자식에 `key`를 할당 함으로써 독자적으로 식별할 수 있습니다.
```javascript
render: function() {
var results = this.props.results;
return (
<ol>
{results.map(function(result) {
return <li key={result.id}>{result.text}</li>;
})}
</ol>
);
}
```
React가 키가 있는 자식들을 비교조정할 때, React는 `key`가 있는 자식이 (오염(clobbered)되는 대신) 재배치되고 (재사용되는 대신) 파괴되도록 보장할 것입니다.
`key`*항상* 배열 안의 각 컴포넌트의 컨테이너 HTML 자식이 아닌 컴포넌트에게 직접 주어져야 합니다.
```javascript
// 틀림!
var ListItemWrapper = React.createClass({
render: function() {
return <li key={this.props.data.id}>{this.props.data.text}</li>;
}
});
var MyComponent = React.createClass({
render: function() {
return (
<ul>
{this.props.results.map(function(result) {
return <ListItemWrapper data={result}/>;
})}
</ul>
);
}
});
// 맞음 :)
var ListItemWrapper = React.createClass({
render: function() {
return <li>{this.props.data.text}</li>;
}
});
var MyComponent = React.createClass({
render: function() {
return (
<ul>
{this.props.results.map(function(result) {
return <ListItemWrapper key={result.id} data={result}/>;
})}
</ul>
);
}
});
```
ReactFragment 객체를 넘기는 것으로 자식에 키를 할당할 수도 있습니다. 자세한 내용은 [키가 할당된 프래그먼트](create-fragment-ko-KR.html)를 참고하세요.
## 데이터 흐름
React에서 데이터는 위에서 말한 것처럼 `props`를 통해 소유자로부터 소유한 컴포넌트로 흐릅니다. 이것은 사실상 단방향 데이터 바인딩입니다. 소유자는 `props``state`를 기준으로 계산한 어떤 값으로 소유한 컴포넌트의 props를 바인드합니다. 이 과정은 재귀적으로 발생하므로, 데이터의 변경은 자동으로 모든 곳에 반영됩니다.
## 성능의 주의점
소유자가 가지고 있는 노드의 수가 많아지면 데이터의 변화에 반응하는 비용이 증가할 것으로 생각할 수도 있습니다. 좋은 소식은 JavaScript의 속도는 빠르고 `render()` 메소드는 꽤 간단한 경향이 있어, 대부분 애플리케이션에서 매우 빠르다는 점입니다. 덧붙여, 대부분의 병목 현상은 JS 실행이 아닌 DOM 변경에서 일어나고, React는 배치와 탐지 변경을 이용해 최적화해 줍니다.
하지만, 가끔 성능을 위해 정교하게 제어해야 할 때도 있습니다. 이런 경우, React가 서브트리의 처리를 건너 뛰도록 간단히 `shouldComponentUpdate()`를 오버라이드해 false를 리턴하게 할 수 있습니다. 좀 더 자세한 정보는 [React 참조 문서](/react/docs/component-specs-ko-KR.html)를 보세요.
> 주의:
>
> 데이터가 실제로는 변경되었지만 `shouldComponentUpdate()`가 false를 리턴한다면 React는 UI를 싱크시킬수 없습니다. 이 기능을 사용할 때에는 자신이 지금 무엇을 하고 있는지 알고 있고, 눈에 띄는 성능 문제가 있을 경우에만 사용하세요. JavaScript는 DOM에 비해 빠릅니다. 과소평가하지 마세요.

View File

@@ -0,0 +1,231 @@
---
id: reusable-components-ko-KR
title: 재사용가능한 컴포넌트
permalink: reusable-components-ko-KR.html
prev: multiple-components-ko-KR.html
next: transferring-props-ko-KR.html
---
인터페이스를 설계할 때, 공통적으로 사용되는 디자인 요소들(버튼, 폼 필드, 레이아웃 컴포넌트 등)을 잘 정의된 인터페이스의 재사용 가능한 컴포넌트로 분해합니다. 이런 방법으로 다음에 UI를 구축할 때에는 훨씬 적은 코드로 만들 수 있습니다. 이 말은 더 빠른 개발 시간, 더 적은 버그, 더 적은 용량으로 할 수 있다는 뜻이죠.
## Prop 검증
앱의 규모가 커지면 컴포넌트들이 바르게 사용되었는지 확인하는게 도움이 됩니다. 확인은 `propTypes`를 명시해서 할 수 있습니다. `React.PropTypes`는 받은 데이터가 적절한지(valid) 확인하는데 사용할 수 있는 다양한 검증자(validator)를 제공합니다. prop에 부적절한 값을 명시한다면 JavaScript 콘솔에 경고가 보일 것입니다. 성능상의 문제로 `propTypes`는 개발 모드에서만 검사됩니다. 다음은 제공되는 검증자를 설명하는 예제입니다.
```javascript
React.createClass({
propTypes: {
// 특정 JavaScript 프리미티브 타입에 대한 prop을 명시할 수 있습니다.
// 기본적으로 이것들은 모두 선택적입니다.
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
// 렌더링될 수 있는 모든 것: 숫자, 문자열, 요소
// 이것들을 포함하는 배열(이나 프래그먼트)
optionalNode: React.PropTypes.node,
// React 엘리먼트
optionalElement: React.PropTypes.element,
// 클래스의 인스턴스 또한 prop으로 명시할 수 있습니다. JavaScript의 instanceof
// 연산자를 사용합니다.
optionalMessage: React.PropTypes.instanceOf(Message),
// 열거형처럼 특정 값들로만 prop을 제한해서 사용할 수 있습니다.
optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
// 많은 타입들 중 하나로 사용할 수 있는 객체가 될 수도 있습니다.
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Message)
]),
// 특정 타입의 배열
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
// 특정 타입의 속성값을 갖는 객체
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
// 특정한 형태(shape)의 객체
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
}),
// 위에 언급된 것들을 `isRequired`로 연결해서 prop이 제공되지 않을 때 경고를
// 띄우도록 할 수도 있습니다.
requiredFunc: React.PropTypes.func.isRequired,
// 어떤 데이터 타입도 가능
requiredAny: React.PropTypes.any.isRequired,
// 물론 사용자 정의 검증자도 지정할 수 있습니다. 이는 검증이 실패했을 때
// Error 객체를 리턴해야합니다. `console.warn`을 이나 throw를 하면 안됩니다.
// 그렇게하면 `oneOfType` 안에서 작동하지 않습니다.
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error('Validation failed!');
}
}
},
/* ... */
});
```
## 기본 Prop 값
React는 매우 선언적(declarative)인 방법으로 `props`의 기본값을 정의할 수 있게 해줍니다.
```javascript
var ComponentWithDefaultProps = React.createClass({
getDefaultProps: function() {
return {
value: 'default value'
};
}
/* ... */
});
```
`getDefaultProps()`의 결과값은 캐시가 되며, 부모 컴포넌트에서 명시되지 않았을 때 `this.props.value`가 값을 가질 수 있도록 해주는데 사용됩니다.`getDefaultProps()`를 사용하면 반복적이고 깨지기 쉬운 코드를 짤 필요없이 그냥 안전하게 prop을 사용할 수 있습니다.
## Prop 전달하기: 단축
React 컴포넌트의 흔히 그냥 기본 HTML 엘리먼트를 확장해서 씁니다. 타이핑을 아끼기 위해 기저의 HTML 엘리먼트에 HTML 속성들을 단순히 복사하는 컴포넌트가 필요할 수도 있습니다. JSX의 _spread_ 문법을 사용하면 이렇게 할 수 있습니다.
```javascript
var CheckLink = React.createClass({
render: function() {
// 모든 prop을 받아서 CheckLink에 넘기고 <a>에 복사합니다.
return <a {...this.props}>{'√ '}{this.props.children}</a>;
}
});
React.render(
<CheckLink href="/checked.html">
Click here!
</CheckLink>,
document.getElementById('example')
);
```
## 단일 자식
`React.PropTypes.element`을 통해 컴포넌트에 한 자식만 보내도록 명시할 수 있습니다.
```javascript
var MyComponent = React.createClass({
propTypes: {
children: React.PropTypes.element.isRequired
},
render: function() {
return (
<div>
{this.props.children} // 정확히 한 엘리먼트여야만 하며, 아니면 에러가 발생합니다.
</div>
);
}
});
```
## 믹스인
컴포넌트는 React에서 코드를 재사용할 수 있는 최고의 방법이지만, 가끔 아주 다른 컴포넌트에서 공통 기능이 필요한 때도 있습니다. 이런 상황을 [공통된 관심사(cross-cutting concerns)](http://en.wikipedia.org/wiki/Cross-cutting_concern)라 부르며, React에서는 `mixins`으로 이 문제를 해결합니다.
예를 들어, 컴포넌트가 주기적으로 업데이트되길 원할 경우가 있습니다. `setInterval()`을 사용하면 쉽지만, 필요 없어지면 메모리를 아끼기 위해 주기를 꼭 취소해야 합니다. React는 컴포넌트가 막 생성거나 없어질 때를 [생명주기 메소드](/react/docs/working-with-the-browser-ko-KR.html#component-lifecycle)를 통해 알려줍니다. 이런 메소드들을 사용해서 컴포넌트가 사라질 때 자동으로 정리해주는 `setInterval()`를 제공해주는 간단한 믹스인을 만들어보겠습니다.
```javascript
var SetIntervalMixin = {
componentWillMount: function() {
this.intervals = [];
},
setInterval: function() {
this.intervals.push(setInterval.apply(null, arguments));
},
componentWillUnmount: function() {
this.intervals.forEach(clearInterval);
}
};
var TickTock = React.createClass({
mixins: [SetIntervalMixin], // 믹스인 사용
getInitialState: function() {
return {seconds: 0};
},
componentDidMount: function() {
this.setInterval(this.tick, 1000); // 믹스인에 있는 메소드를 호출
},
tick: function() {
this.setState({seconds: this.state.seconds + 1});
},
render: function() {
return (
<p>
React has been running for {this.state.seconds} seconds.
</p>
);
}
});
React.render(
<TickTock />,
document.getElementById('example')
);
```
믹스인의 괜찮은 점은 컴포넌트가 여러 믹스인을 사용하고 여러 믹스인에서 같은 생명주기 메소드를 사용할 때(예를 들어, 여러 믹스인에서 컴포넌트가 사라질 때 뭔가 정리하려 한다면) 모든 생명주기 메소드들의 실행은 보장됩니다. 믹스인에 정의된 메소드은 컴포넌트의 메소드가 호출됨에 따라 믹스인이 나열된 순서대로 실행됩니다.
## ES6 클래스
React 클래스를 일반적인 JavaScript 클래스로 선언할 수도 있습니다. 다음의 예제는 ES6 클래스 문법을 사용합니다:
```javascript
class HelloMessage extends React.Component {
render() {
return <div>Hello {this.props.name}</div>;
}
}
React.render(<HelloMessage name="Sebastian" />, mountNode);
```
API는 `getInitialState`를 제외하고 `React.createClass`와 유사합니다. 별도의 `getInitialState` 메소드 대신에, 필요한 `state` 프로퍼티를 생성자에서 설정할 수 있습니다.
또다른 차이점은 `propTypes``defaultProps`가 클래스의 내부가 아니라 생성자의 프로퍼티로 정의되어 있다는 것입니다.
```javascript
export class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {count: props.initialCount};
}
tick() {
this.setState({count: this.state.count + 1});
}
render() {
return (
<div onClick={this.tick.bind(this)}>
Clicks: {this.state.count}
</div>
);
}
}
Counter.propTypes = { initialCount: React.PropTypes.number };
Counter.defaultProps = { initialCount: 0 };
```
### 자동 바인딩 안됨
메소드는 일반 ES6 클래스와 동일한 시멘틱을 따릅니다. `this`를 인스턴스에 자동으로 바인딩하지 않는다는 이야기입니다. 명시적으로 `.bind(this)`나 화살표 함수(arrow function)을 사용하세요.
### 믹스인 안됨
불행하게도 ES6는 믹스인에 대한 지원이 없이 출시되었기 때문에, React에서 ES6 클래스를 사용한다면 믹스인을 사용할 방법이 없습니다. 대신, 우리는 믹스인에 의존하지 않고도 동작하도록 만들기 위해 열심히 노력하고 있습니다.

View File

@@ -100,7 +100,7 @@ The result of `getDefaultProps()` will be cached and used to ensure that `this.p
## Transferring Props: A Shortcut
A common type of React component is one that extends a basic HTML in a simple way. Often you'll want to copy any HTML attributes passed to your component to the underlying HTML element to save typing. You can use the JSX _spread_ syntax to achieve this:
A common type of React component is one that extends a basic HTML element in a simple way. Often you'll want to copy any HTML attributes passed to your component to the underlying HTML element to save typing. You can use the JSX _spread_ syntax to achieve this:
```javascript
var CheckLink = React.createClass({
@@ -200,7 +200,7 @@ class HelloMessage extends React.Component {
React.render(<HelloMessage name="Sebastian" />, mountNode);
```
The API is similar to `React.createClass` with the exception or `getInitialState`. Instead of providing a separate `getInitialState` method, you set up your own `state` property in the constructor.
The API is similar to `React.createClass` with the exception of `getInitialState`. Instead of providing a separate `getInitialState` method, you set up your own `state` property in the constructor.
Another difference is that `propTypes` and `defaultProps` are defined as properties on the constructor instead of in the class body.

View File

@@ -0,0 +1,164 @@
---
id: transferring-props-ko-KR
title: Props 전달
permalink: transferring-props-ko-KR.html
prev: reusable-components-ko-KR.html
next: forms-ko-KR.html
---
React에서는 컴포넌트를 감싸서 추상화하는 것이 일반적인 패턴입니다. 외부 컴포넌트에서는 간단한 프로퍼티만을 노출하여 복잡한 세부 구현을 감출 수 있습니다.
[JSX 스프레드 어트리뷰트](/react/docs/jsx-spread-ko-KR.html)를 통해 props에 추가적인 값을 병합할 수 있습니다.
```javascript
return <Component {...this.props} more="values" />;
```
만약 JSX를 사용하지 않는다면 ES6의 `Object.assign`나 Underscore의 `_.extend` 같은 객체 헬퍼를 사용할 수 있습니다:
```javascript
return Component(Object.assign({}, this.props, { more: 'values' }));
```
이 튜토리얼의 나머지 부분은 모범 답안을 소개할 것입니다. JSX와 실험적인 ES7 구문을 사용합니다.
## 수동적인 전달
대부분의 경우 명시적으로 프로퍼티를 아래로 전달해야 합니다. 이는 동작을 확신하는 내부 API의 일부만 공개하도록 합니다.
```javascript
var FancyCheckbox = React.createClass({
render: function() {
var fancyClass = this.props.checked ? 'FancyChecked' : 'FancyUnchecked';
return (
<div className={fancyClass} onClick={this.props.onClick}>
{this.props.children}
</div>
);
}
});
React.render(
<FancyCheckbox checked={true} onClick={console.log.bind(console)}>
세상아 안녕!
</FancyCheckbox>,
document.getElementById('example')
);
```
하지만 `name`이나 `title`, `onMouseOver` 같은 prop들이 더 추가된다면 어떨까요?
## JSX에서 `...`를 사용해 전달하기
> 주의:
>
> 아래의 예제에서는 실험적인 ES7 문법이 사용되었기 때문에 `--harmony ` 플래그가 필요합니다. 브라우저에서 JSX 변환기를 사용 중이라면, `<script type="text/jsx;harmony=true">`를 사용해 스크립트를 작성하세요. 자세히 알아보려면 아래의 [잔여 프로퍼티와 스프레드 프로퍼티 ...](http://facebook.github.io/react/docs/transferring-props-ko-KR.html#rest-and-spread-properties-...)를 확인하세요.
때로는 모든 프로퍼티를 일일이 전달 하는것은 지루하고 덧없는 작업입니다. 이 경우 [구조 해체 할당(destructuring assignment)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)을 다른 프로퍼티를 함께 사용해 미상의 프로퍼티를 추출할 수 있습니다.
소비할 프로퍼티들을 나열하고, 그 뒤에 `...other`를 넣습니다.
```javascript
var { checked, ...other } = this.props;
```
이는 지금 소비한 props를 *제외한* 나머지를 아래로 전달합니다.
```javascript
var FancyCheckbox = React.createClass({
render: function() {
var { checked, ...other } = this.props;
var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
// `other`에는 { onClick: console.log }가 포함되지만 checked 프로퍼티는 제외됩니다
return (
<div {...other} className={fancyClass} />
);
}
});
React.render(
<FancyCheckbox checked={true} onClick={console.log.bind(console)}>
세상아 안녕!
</FancyCheckbox>,
document.getElementById('example')
);
```
> 주의:
>
> 위의 예제에서는 `checked` prop 또한 마찬가지로 유효한 DOM 어트리뷰트입니다. 이런 식으로 구조의 해체(destructuring)를 하지 않으면 의도하지 않게 함께 전달될 수 있습니다.
미상의 `other` props을 전달할 때는 항상 구조 해체 패턴을 사용하세요.
```javascript
var FancyCheckbox = React.createClass({
render: function() {
var fancyClass = this.props.checked ? 'FancyChecked' : 'FancyUnchecked';
// 반례: `checked` 또한 내부 컴포넌트로 전달될 것입니다
return (
<div {...this.props} className={fancyClass} />
);
}
});
```
## 같은 Prop을 소비하고 전달하기
컴포넌트가 프로퍼티를 사용하지만 계속 넘겨야한다면, `checked={checked}`처럼 명시적으로 다시 넘길 수 있습니다. 리팩토링과 린트(lint)하기가 더 쉬우므로 이 방식이 `this.props` 객체 전부를 넘기는 것보다 낫습니다.
```javascript
var FancyCheckbox = React.createClass({
render: function() {
var { checked, title, ...other } = this.props;
var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
var fancyTitle = checked ? 'X ' + title : 'O ' + title;
return (
<label>
<input {...other}
checked={checked}
className={fancyClass}
type="checkbox"
/>
{fancyTitle}
</label>
);
}
});
```
> 주의:
>
> 순서는 중요합니다. `{...other}`를 JSX props 이전에 넣는 것으로 컴포넌트의 사용자가 확실히 그것들을 오버라이드 할 수 없게 합니다. 위의 예제에서는 input이 `"checkbox"` 타입인 것을 보장합니다.
<a name="rest-and-spread-properties-..."></a>
## 잔여 프로퍼티와 스프레드 프로퍼티 `...`
잔여(Rest, `...`) 프로퍼티는 객체에서 소비되지 않은 나머지 프로퍼티를 추출해 새로운 객체로 만들 수 있게 해 줍니다. 구조 해체 패턴에서 열거된 다른 프로퍼티들은 모두 제외됩니다.
이는 [ES7 제안](https://github.com/sebmarkbage/ecmascript-rest-spread)의 실험적인 구현체입니다.
```javascript
var { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x; // 1
y; // 2
z; // { a: 3, b: 4 }
```
> 주의:
>
> 실험적인 ES7 구문을 활성화하려면 [JSX 커맨드라인 도구](http://npmjs.org/package/react-tools)를 `--harmony` 플래그와 함께 사용하세요.
## Underscore로 전달 다루기
JSX를 사용하지 않는다면 라이브러리를 사용해 같은 패턴을 쓸 수 있습니다. Underscore에서는 `_.omit`을 사용해 특정 프로퍼티를 제외하거나 `_.extend`를 사용해 새로운 객체로 프로퍼티를 복사할 수 있습니다.
```javascript
var FancyCheckbox = React.createClass({
render: function() {
var checked = this.props.checked;
var other = _.omit(this.props, 'checked');
var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
return (
React.DOM.div(_.extend({}, other, { className: fancyClass }))
);
}
});
```

View File

@@ -11,13 +11,13 @@ It's a common pattern in React to wrap a component in an abstraction. The outer
You can use [JSX spread attributes](/react/docs/jsx-spread.html) to merge the old props with additional values:
```javascript
return <Component {...this.props} more="values" />;
<Component {...this.props} more="values" />
```
If you don't use JSX, you can use any object helper such as ES6 `Object.assign` or Underscore `_.extend`:
```javascript
return Component(Object.assign({}, this.props, { more: 'values' }));
React.createElement(Component, Object.assign({}, this.props, { more: 'values' }));
```
The rest of this tutorial explains best practices. It uses JSX and experimental ES7 syntax.
@@ -41,7 +41,7 @@ React.render(
<FancyCheckbox checked={true} onClick={console.log.bind(console)}>
Hello world!
</FancyCheckbox>,
document.body
document.getElementById('example')
);
```
@@ -78,7 +78,7 @@ React.render(
<FancyCheckbox checked={true} onClick={console.log.bind(console)}>
Hello world!
</FancyCheckbox>,
document.body
document.getElementById('example')
);
```

View File

@@ -42,7 +42,7 @@ React.render(
<FancyCheckbox checked={true} onClick={console.log.bind(console)}>
Hello world!
</FancyCheckbox>,
document.body
document.getElementById('example')
);
```
@@ -76,7 +76,7 @@ React.render(
<FancyCheckbox checked={true} onClick={console.log.bind(console)}>
Hello world!
</FancyCheckbox>,
document.body
document.getElementById('example')
);
```

151
docs/docs/07-forms.ko-KR.md Normal file
View File

@@ -0,0 +1,151 @@
---
id: forms-ko-KR
title: 폼
permalink: forms-ko-KR.html
prev: transferring-props-ko-KR.html
next: working-with-the-browser-ko-KR.html
---
`<input>`, `<textarea>`, `<option>` 같은 폼 컴포넌트는 다른 네이티브 컴포넌트와 다릅니다. 왜냐하면, 사용자의 상호작용에 의해 변경될 수 있기 때문이죠. 이런 컴포넌트들은 사용자의 상호작용에 반응하여 폼을 더 쉽게 관리할 수 있도록 인터페이스를 제공합니다.
`<form>` 이벤트에 관한 정보는 [폼 이벤트](/react/docs/events-ko-KR.html#form-events)를 보세요.
## Props의 상호작용
폼 컴포넌트는 사용자 상호작용을 통해 영향을 받는 몇 가지 props를 지원합니다.
* `value`: `<input>`, `<textarea>` 컴포넌트에서 사용가능.
* `checked`: `checkbox`, `radio`타입의 `<input>` 컴포넌트에서 사용가능.
* `selected`: `<option>` 컴포넌트에서 사용가능.
HTML에서는 `<textarea>` 태그의 값을 설정할 때 `<textarea>` 태그의 자식이 사용되지만, React에서는 `value` 를 사용해야 합니다.
폼 컴포넌트는 `onChange` prop의 콜백을 설정하여 변경을 감시(listening)할 수 있습니다. `onChange` prop는 브라우저에 관계없이 다음과 같은 사용자 상호작용에 반응합니다.
* `<input>`, `<textarea>``value` 변경.
* `<input>``checked` state 변경.
* `<option>``selected` state 변경.
모든 DOM 이벤트처럼 `onChange` prop은 모든 네이티브 컴포넌트에서 지원되며 일어난(bubbled) 변경 이벤트를 감시하는데 사용할 수 있습니다.
## 제어되는(controlled) 컴포넌트
`value`가 설정된 `<input>`*제어되는* 컴포넌트입니다. 제어되는 `<input>`에서, 렌더 엘리먼트의 값은 항상 `value` prop을 반영합니다. 예를 들어,
```javascript
render: function() {
return <input type="text" value="Hello!" />;
}
```
이것은 항상 `Hello!`의 값을 가지는 input을 렌더합니다. 어떤 사용자 입력도 렌더된 엘리먼트에는 영향을 주지 않는데, 왜냐하면 React가 값을 `Hello!`로 설정했기 때문입니다. 사용자 입력에 따라 값을 업데이트하길 원한다면, `onChange` 이벤트를 사용할 수 있습니다.
```javascript
getInitialState: function() {
return {value: 'Hello!'};
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
render: function() {
var value = this.state.value;
return <input type="text" value={value} onChange={this.handleChange} />;
}
```
이 예제에서는, 단순히 사용자가 주는 최신값을 받고 `<input>` 컴포넌트의 `value` prop을 업데이트하고 있습니다. 이 패턴은 사용자의 상호작용에 반응하거나 검증하는 인터페이스를 쉽게 구현하게 합니다. 예를 들어,
```javascript
handleChange: function(event) {
this.setState({value: event.target.value.substr(0, 140)});
}
```
이것은 사용자 입력을 받아들이지만, 시작에서부터 140자로 값을 자릅니다.
## 제어되지 않는(Uncontrolled) 컴포넌트
`value` 가 없(거나 `null`로 설정되어 있)는 `<input>`*제어되지 않는* 컴포넌트입니다. 제어되지 않는 `<input>`에서 렌더된 엘리먼트의 value값은 사용자의 입력을 반영합니다. 예를 들어,
```javascript
render: function() {
return <input type="text" />;
}
```
이것은 빈 값으로 시작되는 input을 렌더합니다. 임의의 사용자 입력은 즉시 렌더된 엘리먼트에 반영됩니다. 값의 업데이트를 감시하길 원한다면, 제어되는 컴포넌트처럼 `onChange` 이벤트를 사용할 수 있습니다.
비어 있지 않은 값으로 초기화하길 원한다면, `defaultValue` prop로 할 수 있습니다. 예를 들어,
```javascript
render: function() {
return <input type="text" defaultValue="Hello!" />;
}
```
이 예제는 위에있는 **제어되는 컴포넌트**에 더 가깝게 동작할 것입니다.
마찬가지로, `<input>``defaultChecked`를 지원하고 `<select>``defaultValue`를 지원합니다.
## 심화 주제
### 왜 제어되는 컴포넌트인가요?
React에서 `<input>`같은 폼 컴포넌트를 사용하면, 전통적인 폼 HTML을 쓸 때에는 없던 어려운 문제가 있습니다. 예를 들어 HTML에서
```html
<input type="text" name="title" value="Untitled" />
```
이렇게 하면 input은 `Untitled` 값으로 *초기화* 됩니다. 사용자가 input을 업데이트할 때, 노드의 value *프로퍼티*가 변경될 것입니다. 하지만, `node.getAttribute('value')`은 여전히 초기화 때 사용했던 값인 `Untitled`를 리턴합니다.
HTML과 다르게, React 컴포넌트는 초기화 시점 뿐만 아니라, 어떤 시점이라도 반드시 뷰의 state를 나타내야 합니다. 예를 들어 React에서
```javascript
render: function() {
return <input type="text" name="title" value="Untitled" />;
}
```
이 메소드가 어떤 시점에도 뷰를 기술하기 때문에, 텍스트 input의 값은 *언제나* `Untitled`입니다.
### 왜 Textarea에 value를 사용하나요?
HTML에서, `<textarea>`의 값은 보통 그것의 자식들로 설정됩니다.
```html
<!-- 반례: 이렇게 하지 마세요! -->
<textarea name="description">이것은 설명입니다.</textarea>
```
HTML에서는 이렇게 하면 여러 줄의 값을 쉽게 개발자가 넣을 수 있게 합니다. 하지만, React는 JavaScript기 때문에, 우리는 문자열 제한이 없고 개행이 필요하면 `\n`을 사용할 수 있습니다. 이 곳에서는 `value``defaultValue`가 있고, 그것이 자식들의 역할을 모호하게 합니다. 이런 이유로, `<textarea>`의 값을 설정할 때에는 자식들을 사용하지 않아야 합니다.
```javascript
<textarea name="description" value="이것은 설명입니다." />
```
자식들을 사용하기로 *했다면*, 자식들은 `defaultValue`처럼 동작할 것입니다.
### 왜 Select에 value를 사용하나요?
HTML `<select>`에서 선택된 `<option>`은 보통 option의 `selected` 어트리뷰트로 기술됩니다. React에서는 컴포넌트를 관리하기 쉽게 하기 위해, 다음 형식이 대신 채용됐습니다.
```javascript
<select value="B">
<option value="A">Apple</option>
<option value="B">Banana</option>
<option value="C">Cranberry</option>
</select>
```
제어되지 않는 컴포넌트로 만드려면, 대신 `defaultValue`를 사용하세요.
> 주의:
>
> `select` 태그에 여러 옵션을 선택할 수 있도록, `value` 어트리뷰트에 배열을 넘길 수도 있습니다. `<select multiple={true} value={['B', 'C']}>`

View File

@@ -87,7 +87,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 `defaultValue` and `<select>` supports `defaultChecked`.
Likewise, `<input>` supports `defaultChecked` and `<select>` supports `defaultValue`.
## Advanced Topics

View File

@@ -0,0 +1,147 @@
---
id: working-with-the-browser-ko-KR
title: 브라우저에서의 동작
permalink: working-with-the-browser-ko-KR.html
prev: forms-ko-KR.html
next: more-about-refs-ko-KR.html
---
React는 대부분의 경우 직접 DOM을 다루지 않아도 될만큼 강력한 추상화를 제공합니다. 하지만 서드파티 라이브러리나 기존의 코드들을 다루다 보면 간혹 기저(underlying)의 API에 접근해야 할 때도 있습니다.
## 가상의 DOM
React는 DOM을 직접 다루지 않기 때문에 굉장히 빠릅니다. React는 메모리에(in-memory) DOM의 표상(representation)을 관리합니다. `render()` 메소드는 DOM의 *서술*를 반환하고, React는 이를 메모리에 있는 DOM의 표상과 비교(diff)해 가장 빠른 방식으로 계산해서 브라우저를 업데이트해 줍니다.
게다가 React는 브라우저의 괴악함(quirks)에도 불구하고 모든 이벤트 객체가 W3C 명세를 보장하도록 통합적인 이벤트 시스템을 구현했습니다. 모든 것이 일관된 방식으로 일어나고(bubbles) 효율적인 방식으로 크로스 브라우징을 수행합니다. 심지어 IE8에서도 HTML5 이벤트를 사용할 수 있습니다!
더 효율적이고 쉬우므로 대개의 경우 React의 "가짜 브라우저"를 이용해 작업을 하게 될 것입니다. 하지만 간혹 jQuery 플러그인 같은 서드파티 라이브러리를 다루다 보면 기저(underlying)의 API에 접근할 필요가 있을지도 모릅니다. React는 기저의 DOM API를 직접 다루는 회피방법을 제공합니다.
## Refs와 findDOMNode()
브라우저와 상호 작용하려면 DOM 노드에 대한 참조가 필요합니다. React는 `React.findDOMNode(component)` 함수를 갖고 있으며, 이를 통해서 컴포넌트의 DOM 노드의 참조를 얻을 수 있습니다.
> 주의:
>
> `findDOMNode()`는 마운트 된 컴포넌트에서만 동작합니다 (DOM에 배치된 컴포넌트를 말합니다). 아직 마운트 되지 않은 컴포넌트에서 이를 호출하려고 하면 (컴포넌트가 아직 생성되기 이전인 `render()` 시점에 `findDOMNode()`를 호출한다든가) 예외가 발생합니다.
React 컴포넌트에 대한 참조는 현재의 React 컴포넌트를 위해 `this`를, 소유한 컴포넌트의 참조를 얻기 위해 refs를 사용해 얻을 수 있습니다. 다음과 같이 동작합니다:
```javascript
var MyComponent = React.createClass({
handleClick: function() {
// raw DOM API를 사용해 명시적으로 텍스트 인풋을 포커스 합니다.
React.findDOMNode(this.refs.myTextInput).focus();
},
render: function() {
// ref 어트리뷰트는 컴포넌트가 마운트되면 그에 대한 참조를 this.refs에 추가합니다.
return (
<div>
<input type="text" ref="myTextInput" />
<input
type="button"
value="Focus the text input"
onClick={this.handleClick}
/>
</div>
);
}
});
React.render(
<MyComponent />,
document.getElementById('example')
);
```
## Refs 심화
[refs 심화](/react/docs/more-about-refs-ko-KR.html) 문서에서 refs를 효율적으로 사용하는 법을 포함해 더 많은 내용을 익혀보세요.
<a name="component-lifecycle"></a>
## 컴포넌트 생명주기
컴포넌트의 생명주기에는 세 가지 주요 부분이 있습니다:
* **Mounting:** 컴포넌트가 DOM에 삽입되고 있습니다.
* **Updating:** 컴포넌트가 DOM의 업데이트 여부를 결정하기 위해 다시 렌더링되고 있습니다.
* **Unmounting:** 컴포넌트가 DOM에서 제거되고 있습니다.
React는 이 프로세스에 훅을 지정할 수 있는 생명주기 메소드를 제공합니다. 발생 직전 시점을 위한 **will** 메소드, 발생 직후 시점을 위한 **did** 메소드가 있습니다.
### Mounting
* `getInitialState(): object`는 컴포넌트가 마운트되기 전에 호출됩니다. 상태기반 컴포넌트는 이를 구현하고 초기 상태 데이터를 리턴합니다.
* `componentWillMount()`는 마운팅되기 직전에 호출됩니다.
* `componentDidMount()`는 마운팅 직후 호출됩니다. 초기화에 필요한 DOM 노드는 이곳에 있어야 합니다.
### Updating
* `componentWillReceiveProps(object nextProps)`는 마운트된 컴포넌트가 새로운 props을 받을 때 호출됩니다. 이 메소드는 `this.props``nextProps`을 비교하여 `this.setState()`를 사용해 상태 변환을 수행하는데 사용되야 합니다.
* `shouldComponentUpdate(object nextProps, object nextState): boolean`는 컴포넌트가 어떤 변경이 DOM의 업데이트를 보증하는지 결정해야 할 때 호출됩니다. 최적화하려면, React가 업데이트를 무시해야할 때 `this.props``nextProps`를, `this.state``nextState`를 비교해 false를 리턴하면 됩니다.
* `componentWillUpdate(object nextProps, object nextState)`는 업데이트가 발생하기 직전에 호출됩니다. 이 시점에는 `this.setState()`를 호출할 수 없습니다.
* `componentDidUpdate(object prevProps, object prevState)`는 업데이트가 발생한 후 즉시 호출됩니다.
### Unmounting
* `componentWillUnmount()`는 컴포넌트가 언마운트되어 파괴되기 직전에 호출됩니다. 정리(Cleanup)는 여기서 처리해야 합니다.
### Mounted 메소드
_마운트된_ 합성 컴포넌트들은 다음과 같은 메소드를 지원합니다:
* `findDOMNode(): DOMElement`는 렌더링 된 DOM 노드에 대한 참조를 얻기 위해 모든 마운트된 컴포넌트에서 호출할 수 있습니다.
* `forceUpdate()``this.setState`를 사용하지 않고 컴포넌트 state의 더 깊은 측면(deeper aspect)의 변경된 것을 알고 있을 때 모든 마운트된 컴포넌트에서 호출할 수 있습니다.
## 브라우저 지원과 Polyfill
페이스북에서 우리는 IE8을 포함한 구식 브라우저를 지원합니다. 미래지향적인 JS를 작성할 수 있도록 우리는 polyfill을 오랫동안 써왔습니다. 이는 우리의 코드베이스에 구식 브라우저를 위한 코드뭉치를 흩뿌려 놓을 필요가 없으며 그럼에도 우리의 코드가 "잘 작동"할 것이라 예상할 수 있음을 의미합니다. 예를 들어, `+new Date()` 대신에 그냥 `Date.now()`를 사용할 수 있습니다. 오픈소스 React는 우리가 내부에서 사용하는것과 동일하기 때문에, 우리는 이를 통해 미래지향적인 JS를 사용하는 철학을 전달했습니다.
그 철학에 더하여, 우리는 또한 JS 라이브러리의 저자로서 polyfill을 라이브러리에 포함해서 배포하지 않습니다. 만약 모든 라이브러리가 이런 짓을 하면, 같은 polyfill을 여러 번 내리게 되어 쓸모없이 크기만 차지하는 죽은 코드들을 만들 것 입니다. 당신의 제품이 구식 브라우저를 지원해야한다면, [es5-shim](https://github.com/es-shims/es5-shim) 같은 녀석을 사용할 기회가 있었을 겁니다.
### Polyfill은 구식 브라우저를 지원하기 위해 필요하다
[kriskowal's es5-shim](https://github.com/es-shims/es5-shim)의 `es5-shim.js`는 React에 필요한 다음의 기능을 제공합니다:
* `Array.isArray`
* `Array.prototype.every`
* `Array.prototype.forEach`
* `Array.prototype.indexOf`
* `Array.prototype.map`
* `Date.now`
* `Function.prototype.bind`
* `Object.keys`
* `String.prototype.split`
* `String.prototype.trim`
[kriskowal's es5-shim](https://github.com/kriskowal/es5-shim)의 `es5-sham.js`는, React에 필요한 다음의 기능도 제공합니다:
* `Object.create`
* `Object.freeze`
압축되지 않은 React 빌드는 [paulmillr의 console-polyfill](https://github.com/paulmillr/console-polyfill)에서 다음의 기능이 필요합니다.
* `console.*`
`<section>`, `<article>`, `<nav>`, `<header>`, `<footer>`등 HTML5 엘리먼트를 IE8에서 이용하려면 [html5shiv](https://github.com/aFarkas/html5shiv)같은 스크립트가 추가로 필요합니다.
### 크로스 브라우징 이슈
React가 브라우저별 차이점을 썩 잘 추상화하긴 했지만 일부는 한정적이거나 우리가 발견하지 못한 이상한(quirky) 동작을 보여주기도 합니다.
#### IE8에서의 onScroll 이벤트
IE8에서는 `onScroll` 이벤트가 일어나지(bubble) 않으며, IE8은 이벤트의 캡쳐링 단계를 위한 핸들러를 정의하는 API를 갖고 있지 않습니다. 이는 React가 이 이벤트를 이해(listen) 할 방법이 없음을 뜻합니다. 현재 이 이벤트 핸들러는 IE8에서 무시됩니다.
더 많은 정보는 [onScroll doesn't work in IE8](https://github.com/facebook/react/issues/631) GitHub 이슈를 살펴보세요.

View File

@@ -105,12 +105,12 @@ _Mounted_ composite components also support the following methods:
At Facebook, we support older browsers, including IE8. We've had polyfills in place for a long time to allow us to write forward-thinking JS. This means we don't have a bunch of hacks scattered throughout our codebase and we can still expect our code to "just work". For example, instead of seeing `+new Date()`, we can just write `Date.now()`. Since the open source React is the same as what we use internally, we've carried over this philosophy of using forward thinking JS.
In addition to that philosophy, we've also taken the stance that we, as authors of a JS library, should not be shipping polyfills as a part of our library. If every library did this, there's a good chance you'd be sending down the same polyfill multiple times, which could be a sizable chunk of dead code. If your product needs to support older browsers, chances are you're already using something like [es5-shim](https://github.com/kriskowal/es5-shim).
In addition to that philosophy, we've also taken the stance that we, as authors of a JS library, should not be shipping polyfills as a part of our library. If every library did this, there's a good chance you'd be sending down the same polyfill multiple times, which could be a sizable chunk of dead code. If your product needs to support older browsers, chances are you're already using something like [es5-shim](https://github.com/es-shims/es5-shim).
### Polyfills Needed to Support Older Browsers
`es5-shim.js` from [kriskowal's es5-shim](https://github.com/kriskowal/es5-shim) provides the following that React needs:
`es5-shim.js` from [kriskowal's es5-shim](https://github.com/es-shims/es5-shim) provides the following that React needs:
* `Array.isArray`
* `Array.prototype.every`
@@ -123,7 +123,7 @@ In addition to that philosophy, we've also taken the stance that we, as authors
* `String.prototype.split`
* `String.prototype.trim`
`es5-sham.js`, also from [kriskowal's es5-shim](https://github.com/kriskowal/es5-shim), provides the following that React needs:
`es5-sham.js`, also from [kriskowal's es5-shim](https://github.com/es-shims/es5-shim), provides the following that React needs:
* `Object.create`
* `Object.freeze`

View File

@@ -0,0 +1,150 @@
---
id: more-about-refs-ko-KR
title: refs 심화
permalink: more-about-refs-ko-KR.html
prev: working-with-the-browser-ko-KR.html
next: tooling-integration-ko-KR.html
---
render 메소드를 통해 UI 구조를 얻은 다음, 반환된 컴포넌트 인스턴스에 접근하거나 메소드를 호출할 방법이 필요할 수도 있습니다. 반응적 데이터 플로우가 `render()`의 결과물에서 최신의 `props`가 각각의 자식으로 보내진 것을 항상 보장하기 때문에 애플리케이션의 데이터 플로우를 만드는데 대체로 이런 작업은 필요가 없지만, 여전히 이런 작업이 필요하거나 유리한 경우가 있긴 합니다.
인스턴스의 하위 계층구조에 존재하는 `<input />` 엘리먼트의 value를 빈 문자열(`''`)로 업데이트한 후 포커스 하는 경우를 생각해 봅시다.
```javascript
var App = React.createClass({
getInitialState: function() {
return {userInput: ''};
},
handleChange: function(e) {
this.setState({userInput: e.target.value});
},
clearAndFocusInput: function() {
this.setState({userInput: ''}); // 입력내용을 지워줍니다
// 이제 <input />에 포커스를 주길 원합니다!
},
render: function() {
return (
<div>
<div onClick={this.clearAndFocusInput}>
클릭해서 초기화하고 포커스주기
</div>
<input
value={this.state.userInput}
onChange={this.handleChange}
/>
</div>
);
}
});
```
한번 살펴보죠. 이 예제에서 우리는 시간이 지남에 따라 props에서 추론할 수 없는 무언가를 입력하도록 "알려주길" 원했습니다. 이 사례에서 우리는 이제 포커스 되도록 "알려주길" 원합니다. 그러나 몇 가지 문제가 있습니다. `render()`에서 반환된 것은 "자식" 컴포넌트의 실제 구성이 아니고, 단지 특정 시점의 인스턴스의 자식에 대한 *서술*일 뿐입니다. - 말하자면 스냅샷인 것이지요.
> 주의:
>
> 기억하세요, `render()`에서 반환된 것은 *실제* 자식 인스턴스가 아닙니다. 단지 특정 시점의 컴포넌트의 하위 계층구조에 있는 자식 인스턴스의 *서술*일 뿐입니다.
이는 `render()`에서 반환된 무언가를 "계속 유지할 수" 없으며 아무런 의미도 없을 것이라는 뜻입니다.
```javascript
// 반례: 이렇게 하면 안됩니다!
render: function() {
var myInput = <input />; // 여기서 메소드를 호출할 겁니다.
this.rememberThisInput = myInput; // 언젠가 미래의 특정 시점에 입력할 거에요! YAY!
return (
<div>
<div>...</div>
{myInput}
</div>
);
}
```
이 반례에서 `<input />`은 단지 `<input />`의 *서술*일 뿐입니다. 이 서술은 `<input />`에 대한 *진짜* **지원 인스턴스(backing instance)**를 생성하는 데 사용됩니다.
자 그럼 어떻게 *진짜* input의 지원 인스턴스를 다룰까요?
## ref 문자열 어트리뷰트
React는 `render()`로 출력된 컴포넌트에 추가할 수 있는 아주 특별한 프로퍼티를 지원합니다. 이 특별한 프로퍼티는 `render()`에서 반환한 모든 것들에 대해 각각에 대응하는 **지원 인스턴스**를 참조할 수 있습니다. 이는 항상 어떤 시점에서든 올바른 인스턴스를 보장합니다.
간단합니다:
1. `render`에서 반환된 값을 `ref` 어트리뷰트에 할당합니다:
```html
<input ref="myInput" />
```
2. 다른 코드(일반적으로는 이벤트 핸들러 코드)에서 `this.refs`를 통해 **지원 인스턴스**에 접근 합니다:
```javascript
this.refs.myInput
```
`React.findDOMNode(this.refs.myInput)`를 호출해 컴포넌트의 DOM 노드에 접근할 수 있습니다.
## ref 콜백 어트리뷰트
`ref` 어트리뷰트는 이름 대신 콜백 함수가 될 수도 있습니다. 이 콜백은 컴포넌트가 마운트 된 뒤 즉시 실행될 것입니다. 참조된 컴포넌트는 매개 변수로 전달되며 콜백은 이를 즉시 사용하거나, 앞으로 사용하기 위해 참조를 저장해 놓거나, 혹은 둘 다 할 것입니다.
`render`에서 반환한 모든 것에 간단하게 `ref` 어트리뷰트를 할당할 수 있습니다:
```html
<input ref={ function(component){ React.findDOMNode(component).focus();} } />
```
## 예제 완성하기
```javascript
var App = React.createClass({
getInitialState: function() {
return {userInput: ''};
},
handleChange: function(e) {
this.setState({userInput: e.target.value});
},
clearAndFocusInput: function() {
// input을 비워준다
this.setState({userInput: ''}, function() {
// 이 코드는 컴포넌트가 다시 렌더 된 다음 실행됩니다
React.findDOMNode(this.refs.theInput).focus(); // 짠! 포커스 됨!
});
},
render: function() {
return (
<div>
<div onClick={this.clearAndFocusInput}>
클릭해서 초기화하고 포커스주기
</div>
<input
ref="theInput"
value={this.state.userInput}
onChange={this.handleChange}
/>
</div>
);
}
});
```
이 예제에서 render 함수는 `<input />` 인스턴스의 서술을 반환했지만, 진짜 인스턴스는 `this.refs.theInput`을 통해 접근할 수 있었습니다. render에서 `ref="theInput"`을 가진 컴포넌트가 반환된 동안, `this.refs.theInput`은 적절한 인스턴스에 접근합니다. 이는 `<Typeahead ref="myTypeahead" />`처럼 DOM이 아닌 고수준의 컴포넌트에서도 동작합니다.
## 요약
Refs는 반응적인 `props`와 `state` 스트리밍을 통해서는 불편했던 특정한 자식 인스턴스에 메시지 보내기를 수행하는 좋은 방법입니다. 하지만 애플리케이션의 데이터 플로우 전반에 사용해도 되는 go-to 같은 개념은 아닙니다. 기본적으로는 반응적인 데이터 플로우를 사용하고, `ref`는 근본적으로 반응적이지 않은 경우에만 사용하세요.
### 이점:
- 컴포넌트 클래스에 public 메소드(ex. Typeahead의 reset)를 선언할 수 있으며 refs를 통해 그를 호출할 수 있습니다. (ex. `this.refs.myTypeahead.reset()`)
- DOM을 측정하기 위해서는 거의 항상 `<input />` 같은 "기본" 컴포넌트를 다루고 `React.findDOMNode(this.refs.myInput)`를 통해 그 기저의 DOM 노드에 접근해야 합니다. Refs는 이 일을 확실하게 수행하는 몇 안 되는 실용적인 방법의 하나입니다.
- Refs는 자동으로 기록을 관리합니다! 자식이 파괴되면, 그의 ref도 마찬가지로 파괴됩니다. 참조를 유지하기 위해 뭔가 미친 짓을 하지 않는 한, 메모리 걱정은 하지 않아도 됩니다.
### 주의:
- 컴포넌트의 렌더 메소드에서는, 혹은 컴포넌트의 렌더 메소드가 콜스택 어디에서든 실행되는 동안에는 절대 접근하지 마세요.
- Google Closure Compiler에서의 분쇄 복원력 유지(to preserve Crushing resilience)를 위해서는 문자열로 정의한 것을 절대 프로퍼티로 접근하지 마세요. ref가 ref="myRefString"으로 정의되어 있다면 this.refs['myRefString']으로만 접근해야 한다는 이야기 입니다.
- React로 앱을 여럿 만들어 본 경험이 없다면, 보통은 처음엔 앱에서 "무언가 일어나도록" 하는데 refs를 사용하게 될 것입니다. 이 경우, 잠시 시간을 내어 `state`가 컴포넌트 계층구조의 어느 부분에서 관리되어야 할지 비판적으로 생각해 봅시다. 대개는 state가 계층구조의 더 높은 레벨에서 "소유"하는 것이 타당함이 명확해집니다. 그렇게 함으로써 `ref`를 사용해 "무언가 일어나도록" 하려는 욕망이 대부분 제거됩니다. - 대신에 데이터 플로우를 통해 대개 원하는 바를 달성하게 될 것입니다.

View File

@@ -0,0 +1,44 @@
---
id: tooling-integration-ko-KR
title: 툴 통합
permalink: tooling-integration-ko-KR.html
prev: more-about-refs-ko-KR.html
next: addons-ko-KR.html
---
모든 프로젝트는 JavaScript를 빌드, 배포할 때 다른 시스템을 사용합니다. 우리는 가능한 한 React를 환경에 구속받지 않도록 하려 노력했습니다.
## React
### CDN-호스트 React
[다운로드 페이지](/react/downloads.html)에서 React의 CDN 호스트 버전을 제공합니다. 이 미리 빌드된 파일들은 UMD 모듈 포맷을 사용합니다. 간단한 `<script>` 태그로 넣어보면 `React` 글로벌이 환경으로 주입(inject)될 것입니다. CommonJS와 AMD환경에서 별도의 작업 없이도 동작해야 합니다.
### master 사용하기
[GitHub 저장소](https://github.com/facebook/react)의 `master`에 빌드 방법이 있습니다. 이는 `build/modules`에 CommonJS 모듈 트리를 빌드합니다. 이는 CommonJS를 지원하는 어떤 환경이나 패키징 툴에도 넣을 수 있습니다.
## JSX
### 브라우저에서 JSX 변환
JSX를 사용하신다면, [다운로드 페이지](/react/downloads.html)에서 브라우저 JSX 변환기를 제공합니다. 간단히 `<script type="text/jsx">`를 넣으면 JSX 변환기가 작동합니다.
> 주의:
>
> 브라우저 JSX 변환기는 꽤 크고 안 할 수도 있는 클라이언트 측 연산을 하게 됩니다. 프로덕션 환경에서 사용하지 마시고, 다음 단락을 보세요.
### 상용화하기: 미리 컴파일된 JSX
[npm](http://npmjs.org/) 모듈을 가지고 있다면, 간단히 `npm install -g react-tools`를 실행해 커맨드 라인 `jsx` 툴을 설치할 수 있습니다. 이 툴은 JSX 구문을 일반적인 JavaScript파일로 변환해 브라우져에서 바로 실행할 수 있도록 합니다. 디렉터리를 감시해 파일이 변경되었을 때 자동으로 변환하도록 할 수도 있습니다. 예를 들면 `jsx --watch src/ build/` 이렇게요.
기본적으로는 JSX 파일들은 `.js` 확장자로 변환됩니다. `jsx --extension jsx src/ build/`를 사용해 `.jsx` 확장자로 파일들을 변환할 수 있습니다.
이 툴을 어떻게 사용하는지 더 자세하게 알고싶으시면 `jsx --help`를 실행해 보세요.
### 도움되는 오픈소스 프로젝트들
오픈 소스 커뮤니티는 JSX와 연동하는 여러 에디터와 빌드 시스템을 만들었습니다. 전 목록은 [JSX 연동](https://github.com/facebook/react/wiki/Complementary-Tools#jsx-integrations)에서 보세요.

View File

@@ -0,0 +1,25 @@
---
id: addons-ko-KR
title: 애드온
permalink: addons-ko-KR.html
prev: tooling-integration-ko-KR.html
next: animation-ko-KR.html
---
`React.addons`은 React 앱을 만드는 데 유용한 유틸리티를 두는 곳입니다. **실험적인 기능으로 취급해야 하지만** 결국 코어나 유틸리티 라이브러리에 포함될 예정입니다.
- [`TransitionGroup` 과 `CSSTransitionGroup`](animation-ko-KR.html)은 예를 들면 컴포넌트 삭제 직전의 트랜지션 처럼, 구현하기 까다로운 애니메이션과 트랜지션을 다룹니다.
- [`LinkedStateMixin`](two-way-binding-helpers-ko-KR.html)는 사용자 입력과 컴포넌트의 state사이의 조정(coordination)을 단순화 합니다.
- [`cloneWithProps`](clone-with-props-ko-KR.html)는 React 컴포넌트를 얕은 복사를 하고 props를 변경합니다.
- [`createFragment`](create-fragment-ko-KR.html)는 외부에서 키가 할당된 자식들의 모음을 만듭니다.
- [`update`](update-ko-KR.html)는 JavaScript안에서 불변 데이터를 다루기 쉽게하는 헬퍼 함수입니다.
- [`PureRenderMixin`](pure-render-mixin-ko-KR.html)는 특정 상황에서 성능을 향상시켜 줍니다.
밑에 있는 애드온은 React 개발 (압축되지 않은) 버전에서만 사용가능 합니다.
- [`TestUtils`](test-utils-ko-KR.html)는 테스트 케이스를 적기 위한 간단한 헬퍼입니다. (압축되지 않은 빌드에서만 사용가능)
- [`Perf`](perf-ko-KR.html)는 성능을 측정하고, 최적화를 위한 힌트를 제공합니다.
애드온을 쓰려면, 보통 `react.js` 대신 `react-with-addons.js`(혹은 압축판)을 사용해야 합니다.
npm을 이용해 React 패키지를 설치해 사용한다면, 그냥 `require('react')` 대신 `require('react/addons')`을 사용해 모든 애드온을 쓸 수 있습니다.

View File

@@ -0,0 +1,193 @@
---
id: animation-ko-KR
title: 애니메이션
permalink: animation-ko-KR.html
prev: addons-ko-KR.html
next: two-way-binding-helpers-ko-KR.html
---
React에는 애니메이션을 위한 저 수준 API로 `ReactTransitionGroup` 애드온 컴포넌트가 있고 간단히 기초 CSS 애니메이션과 트랜지션을 구현할 수 있는 `ReactCSSTransitionGroup`가 있습니다.
## 고 레벨 API: `ReactCSSTransitionGroup`
`ReactCSSTransitionGroup``ReactTransitionGroup`를 기반으로 React 컴포넌트가 DOM에 들어가거나 나올때의 CSS의 트랜지션과 애니메이션을 구현하기 쉽게합니다. 이는 [ng-animate](http://www.nganimate.org/) 라이브러리에 영향을 받았습니다.
<a name="getting-stared"></a>
### 시작하기
`ReactCSSTransitionGroup``ReactTransitions`을 위한 인터페이스입니다. 이는 애니메이션을 제어할 모든 컴포넌트를 감싸는 하나의 엘리먼트 입니다. 아래는 목록의 아이템을 페이드 인/아웃하는 간단한 예제입니다.
```javascript{28-30}
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
var TodoList = React.createClass({
getInitialState: function() {
return {items: ['hello', 'world', 'click', 'me']};
},
handleAdd: function() {
var newItems =
this.state.items.concat([prompt('Enter some text')]);
this.setState({items: newItems});
},
handleRemove: function(i) {
var newItems = this.state.items;
newItems.splice(i, 1);
this.setState({items: newItems});
},
render: function() {
var items = this.state.items.map(function(item, i) {
return (
<div key={item} onClick={this.handleRemove.bind(this, i)}>
{item}
</div>
);
}.bind(this));
return (
<div>
<button onClick={this.handleAdd}>Add Item</button>
<ReactCSSTransitionGroup transitionName="example">
{items}
</ReactCSSTransitionGroup>
</div>
);
}
});
```
> 주의:
>
> `ReactCSSTransitionGroup`의 모든 자식은 [`key` 어트리뷰트](/react/docs/multiple-components-ko-KR.html#dynamic-children)를 반드시 만들어야 합니다. 한 아이템을 렌더한다 해도 예외는 아닙니다. 키는 React가 어떤 자식이 들어오고, 나가고, 머무르는지 파악할 때 사용합니다.
이 컴포넌트에서 새로운 아이템이 `ReactCSSTransitionGroup`에 추가되면 `example-enter` 아이템은 CSS 클래스를 가지게 되고 다음 순간에 `example-enter-active` CSS 클래스가 추가됩니다. 이는 `transitionName` prop을 기반으로 한 관례입니다.
이 클래스들은 CSS 애니메이션이나 트랜지션을 일으키는데 사용할 수 있습니다. 예를 들어, 이 CSS를 넣은 후 아이템을 추가해 보세요.
```css
.example-enter {
opacity: 0.01;
transition: opacity .5s ease-in;
}
.example-enter.example-enter-active {
opacity: 1;
}
```
`ReactCSSTransitionGroup`에서 아이템을 제거하려해도 DOM에는 남게 됩니다. 만약 애드온을 React의 최소화하지 않은 빌드와 사용한다면, 애니메이션이나 트랜지션이 일어나는 것을 예상하고 있었다는 React의 경고를 보게 될 것입니다. 그게 바로 `ReactCSSTransitionGroup`가 DOM 엘리먼트를 애니메이션이 끝날 때까지 페이지에 남겨두는 이유입니다. 이 CSS를 넣어보세요.
```css
.example-leave {
opacity: 1;
transition: opacity .5s ease-in;
}
.example-leave.example-leave-active {
opacity: 0.01;
}
```
### 애니메이션 그룹이 작동하려면 마운트가 필요
자식들에게 트랜지션을 적용하려면 `ReactCSSTransitionGroup`은 이미 DOM에 마운트되어 있어야 합니다. 예를 들어, 밑의 코드는 동작하지 않을 것입니다. 왜냐하면 `ReactCSSTransitionGroup` 안에서 새 아이템을 마운트하는 대신 새 아이템과 같이 `ReactCSSTransitionGroup`를 마운트했기 때문입니다. 이 것을 위에 있는 [시작하기](#getting-stared) 항목과 비교해보세요.
```javascript{12-15}
render: function() {
var items = this.state.items.map(function(item, i) {
return (
<div key={item} onClick={this.handleRemove.bind(this, i)}>
<ReactCSSTransitionGroup transitionName="example">
{item}
</ReactCSSTransitionGroup>
</div>
);
}, this);
return (
<div>
<button onClick={this.handleAdd}>Add Item</button>
{items}
</div>
);
}
```
### 아이템 하나이거나 없을 때의 애니메이션
위의 에제에서 `ReactCSSTransitionGroup`에 아이템 목록을 렌더했지만, `ReactCSSTransitionGroup`의 자식은 하나이거나 없을 수도 있습니다. 이는 한 엘리먼트가 들어오고 나가는 것의 애니메이션을 가능하게 합니다. 비슷하게, 현재 엘리먼트가 나가는 동안 새 앨리먼트의 애니메이션을 하면, 새 엘리먼트가 현재 엘리먼트를 교체하는 애니메이션을 만들 수 있습니다. 예를 들어 이렇게 간단한 이미지 회전 베너(carousel)를 구현할 수 있습니다.
```javascript{10-12}
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
var ImageCarousel = React.createClass({
propTypes: {
imageSrc: React.PropTypes.string.isRequired
},
render: function() {
return (
<div>
<ReactCSSTransitionGroup transitionName="carousel">
<img src={this.props.imageSrc} key={this.props.imageSrc} />
</ReactCSSTransitionGroup>
</div>
);
}
});
```
### 애니메이션 비활성화
원한다면 `enter`나 `leave` 애니메이션을 비활성화 할 수 있습니다. 예를 들어, `enter` 애니메이션만 필요하고 `leave` 애니메이션은 필요없지만, `ReactCSSTransitionGroup`이 DOM 노드를 없애기 전 애니메이션이 완료되길 기다리고 있는 경우에 사용할 수 있습니다. `ReactCSSTransitionGroup`에 `transitionEnter={false}`나 `transitionLeave={false}` props를 추가하면 그 애니메이션을 비활성화 할 수 있습니다.
> 주의:
>
> `ReactCSSTransitionGroup`를 사용할 때는, 트랜지션이 종료되었을 때나 애니메이션 근처에서 더 복잡한 로직을 실행할 때 컴포넌트에 통지할 방법이 없습니다. 보다 세밀하게 제어하고 싶다면, 커스텀 트랜지션에 필요한 훅을 제공하는 저수준 `ReactTransitionGroup` API를 이용할 수 있습니다.
## 저수준 API: `ReactTransitionGroup`
`ReactTransitionGroup`은 애니메이션의 기초입니다. 이는 `React.addons.TransitionGroup`으로 접근할 수 있습니다. 위에 있는 예제처럼 자식들이 선언적으로 여기에 추가되거나 삭제되는 경우, 특별한 훅이 이 생명주기에서 호출됩니다.
### `componentWillAppear(callback)`
이미 있는 `TransitionGroup`에 컴포넌트를 추가할 때 호출되는 `componentDidMount()`와 같이 호출됩니다. 이는 `callback`이 호출될 때까지 다른 애니메이션을 막습니다. `TransitionGroup`의 최초 렌더에서만 호출됩니다.
### `componentDidAppear()`
이는 `componentWillAppear`에 넘겨졌던 `callback` 함수가 호출된 다음에 호출됩니다.
### `componentWillEnter(callback)`
이미 있는 `TransitionGroup`에 컴포넌트를 추가할 때 호출되는 `componentDidMount()`와 같이 호출됩니다. 이는 `callback`이 호출될 때까지 다른 애니메이션을 막습니다. `TransitionGroup`의 최조 렌더에서는 불려지지 않습니다.
### `componentDidEnter()`
이는 `componentWillEnter`에 넘겨주었던 `callback` 함수가 호출된 다음에 호출됩니다.
### `componentWillLeave(callback)`
이는 `ReactTransitionGroup`에서 자식이 제거되었을 때 호출됩니다. 자식이 제거되었다고 해도 `ReactTransitionGroup`는 `callback`이 호출될 때까지 DOM에 자식을 남겨둡니다.
### `componentDidLeave()`
이는 `willLeave` `callback`이 호출될 때 호출됩니다. (`componentWillUnmount`와 같은 타이밍)
### 다른 컴포넌트 렌더하기
기본적으로 `ReactTransitionGroup`은 `span`으로 렌더합니다. `component` prop으로 이 행동을 바꿀 수 있습니다. 예를 들어, `<ul>`을 렌더하고 싶다면 이렇게 하면 됩니다.
```javascript{1}
<ReactTransitionGroup component="ul">
...
</ReactTransitionGroup>
```
모든 React가 렌더할 수 있는 DOM 컴포넌트는 사용할 수 있습니다. 하지만 `component`가 DOM 컴포넌트일 필요는 없습니다. React 컴포넌트라면 무엇이든 넣을 수 있습니다. 직접 구현한 컴포넌트여도 됩니다!
> 주의:
>
> v0.12이전에는, DOM 컴포넌트를 사용할 때, `component` prop은 `React.DOM.*`로 참조할 필요가 있었습니다. 이제 컴포넌트가 단순히 `React.createElement`로 전달되기 때문에, `component` prop은 스트링이어야 합니다. 복합 컴포넌트는 팩토리를 넘겨야 합니다.
사용자 정의를 포함한 어떤 프로퍼티도 렌더된 컴포넌트의 프로퍼티가 됩니다. 예를 들어, `<ul>`에 CSS 클래스를 넣어서 렌더하려면 이렇게 하면 됩니다.
```javascript{1}
<ReactTransitionGroup component="ul" className="animated-list">
...
</ReactTransitionGroup>
```

View File

@@ -143,6 +143,14 @@ You can disable animating `enter` or `leave` animations if you want. For example
`ReactTransitionGroup` is the basis for animations. It is accessible as `React.addons.TransitionGroup`. When children are declaratively added or removed from it (as in the example above) special lifecycle hooks are called on them.
### `componentWillAppear(callback)`
This is called at the same time as `componentDidMount()` for components that are initially mounted in a `TransitionGroup`. It will block other animations from occurring until `callback` is called. It is only called on the initial render of a `TransitionGroup`.
### `componentDidAppear()`
This is called after the `callback` function that was passed to `componentWillAppear` is called.
### `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`.

View File

@@ -0,0 +1,114 @@
---
id: two-way-binding-helpers-ko-KR
title: 양방향 바인딩 핼퍼
permalink: two-way-binding-helpers-ko-KR.html
prev: animation-ko-KR.html
next: test-utils-ko-KR.html
---
`ReactLink`는 React에서 양방향 바인딩을 표현하는 쉬운 방법입니다.
> 주의:
>
> 프레임워크를 새로 접하신다면, 대부분의 애플리케이션에서 `ReactLink`는 필요없고 신중히 사용하셔야 함을 알려드립니다.
React에서 데이터 흐름은 소유주에서 자식으로의 단방향입니다. 이는 [폰 노이만 컴퓨팅 모델](http://ko.wikipedia.org/wiki/%ED%8F%B0_%EB%85%B8%EC%9D%B4%EB%A7%8C_%EA%B5%AC%EC%A1%B0)의 데이터가 단방향으로 흐르기 때문입니다. 이것을 "단방향 데이터 바인딩"으로 생각하셔도 됩니다.
하지만 많은 애플리케이션에서 데이터를 요청해서 프로그램으로 돌려줍니다. 예를 들어, 폼을 개발한다면, 사용자 입력을 받았을 때 `state`를 바꾸거나, JavaScript안에서 레이아웃을 바꾸고 그에 따라 어떤 DOM 엘리먼트의 크기를 바꾸게 하고 싶을 수도 있습니다.
React에서 이는 "change" 이벤트를 감시하고 데이터 소스(보통 DOM)에서 읽어 컴포넌트에서 `setState()`를 호출하는 식으로 할 수 있습니다. "데이터 흐름 반복을 제한"하면 더 이해하기 편하고, 쉽게 유지보수할 수 있는 프로그램이 만들어지는 것은 명확합니다. 더 자세한 내용은 [폼 문서](/react/docs/forms-ko-KR.html)를 확인하세요.
양방향 바인딩(묵시적으로 DOM의 어떤 값은 React `state`와 일치하도록 강제하는 것)은 간결하기도 하고 다양한 애플리케이션을 지원 할 수 있습니다. React는 `ReactLink`를 제공합니다. 이는 위에서 설명한 일반적인 데이터 흐름 반복 패턴을 설정하거나, 어떤 데이터 소스를 React `state`로 "링크하는" 편의 문법입니다.
> 주의:
>
> ReactLink는 얇은 레퍼고 `onChange`/`setState()`패턴 부분의 관례일 뿐입니다. React 애플리케이션에서의 데이터 흐름을 근본적으로 바꾸지는 않습니다.
## ReactLink: 적용 전후
`ReactLink`를 사용하지 않는 간단한 폼 예제입니다.
```javascript
var NoLink = React.createClass({
getInitialState: function() {
return {message: '안녕!'};
},
handleChange: function(event) {
this.setState({message: event.target.value});
},
render: function() {
var message = this.state.message;
return <input type="text" value={message} onChange={this.handleChange} />;
}
});
```
이것은 정말 잘 동작하고, 데이터가 어떻게 흐르는지 매우 명확하게 보여지지만, 폼필드가 많을 경우 약간 장황해 질 수 있습니다. 타이핑을 줄이기 위해 `ReactLink`를 사용해 보겠습니다.
```javascript{2,7}
var WithLink = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
},
render: function() {
return <input type="text" valueLink={this.linkState('message')} />;
}
});
```
`LinkedStateMixin`는 React 컴포넌트에 `linkState()`라는 메서드를 추가합니다. `linkState()`는 React state의 현재 값과 그것을 변경할 때의 콜백을 가지는 `ReactLink` 객체를 리턴합니다.
`ReactLink` 객체는 props로 트리의 위나 아래로 넘길 수 있어서, 쉽고 명확하게 계층구조에서 깊이 있는 컴포넌트와 높이 있는 state 사이의 양방향 바인딩을 설정할 수 있습니다.
checkbox의 `value` 어트리뷰트는 다른 것과 다르게 checkbox가 체크되었을 때 폼 submit에 값이 전달되는 것에 주의하세요.(기본값 `on`) 그래서 `value` 어트리뷰트는 checkbox가 체크되거나 해제될 때 업데이트되지 않습니다. checkbox에서는 `valueLink`대신 `checkedLink`를 사용하셔야 합니다.
```
<input type="checkbox" checkedLink={this.linkState('booleanValue')} />
```
## 내부 구조
`ReactLink`에는 크게 인스턴스를 생성하는 면과 사용하는 면이 있습니다. `ReactLink`가 얼마나 간단한지 확인하기 위해, 이 부분들을 보다 명시적으로 고쳐 봅시다.
### LinkedStateMixin 없이 ReactLink 쓰기
```javascript{5-7,9-12}
var WithoutMixin = React.createClass({
getInitialState: function() {
return {message: 'Hello!'};
},
handleChange: function(newValue) {
this.setState({message: newValue});
},
render: function() {
var valueLink = {
value: this.state.message,
requestChange: this.handleChange
};
return <input type="text" valueLink={valueLink} />;
}
});
```
보시다시피, `ReactLink` 객체는 `value`와 `requestChange` prop만 가지는 매우 간단한 객체입니다. `LinkedStateMixin`도 간단합니다. 그냥 `this.state`의 값과 `this.setState()`에서 호출되는 콜백을 필드로 가질 뿐입니다.
### valueLink 없이 ReactLink 쓰기
```javascript
var WithoutLink = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
},
render: function() {
var valueLink = this.linkState('message');
var handleChange = function(e) {
valueLink.requestChange(e.target.value);
};
return <input type="text" value={valueLink.value} onChange={handleChange} />;
}
});
```
`valueLink` prop도 간단합니다. 단순히 `onChange` 이벤트를 처리하고 `this.props.valueLink.requestChange()`를 호출하고 `this.props.value`대신 `this.props.valueLink.value`를 사용합니다. 그게 다에요!

View File

@@ -0,0 +1,62 @@
---
id: class-name-manipulation-ko-KR
title: 클래스 이름 조작
permalink: class-name-manipulation-ko-KR.html
prev: two-way-binding-helpers-ko-KR.html
next: test-utils-ko-KR.html
---
> 주의:
>
> 이 모듈은 이제 [JedWatson/classnames](https://github.com/JedWatson/classnames)에 독립적으로 있고 React와 관련없습니다. 그러므로 이 애드온은 제거될 예정입니다.
`classSet()`은 간단히 DOM `class` 문자열을 조작하는 편리한 도구입니다.
일반적으로 있을법한 경우와 `classSet()`을 사용하지 않았을 때의 처리법을 보시죠.
```javascript
// 어떤 `<Message />` React 컴포넌트의 안쪽
render: function() {
var classString = 'message';
if (this.props.isImportant) {
classString += ' message-important';
}
if (this.props.isRead) {
classString += ' message-read';
}
// 'message message-important message-read'
return <div className={classString}>좋아요, 거기서 봅시다.</div>;
}
```
이것은 순식간에 장황해질 수 있습니다. 클래스 이름 문자열은 읽기 어렵고 에러가 발생하기도 쉽죠. `classSet()`가 이 문제를 해결할 수 있습니다.
```javascript
render: function() {
var cx = React.addons.classSet;
var classes = cx({
'message': true,
'message-important': this.props.isImportant,
'message-read': this.props.isRead
});
// 최종 문자열은 동일하지만, 훨씬 깔끔함
return <div className={classes}>좋아요, 거기서 봅시다.</div>;
}
```
`classSet()`을 사용할 때 사용할지 안할지 잘 모르는 CSS 클래스 이름 키와 함께 객체를 전달합니다. true로 간주되는(Truthy) 값은 키를 결과 문자열의 일부로 만듭니다.
`classSet()`은 클래스 이름을 인자로 넘겨 연결되게 할 수도 있습니다.
```javascript
render: function() {
var cx = React.addons.classSet;
var importantModifier = 'message-important';
var readModifier = 'message-read';
var classes = cx('message', importantModifier, readModifier);
// 최종 문자열은 'message message-important message-read'
return <div className={classes}>좋아요, 거기서 봅시다.</div>;
}
```
복잡한 문자열 연결은 이제 안하셔도 됩니다!

View File

@@ -0,0 +1,181 @@
---
id: test-utils-ko-KR
title: 테스트 유틸리티
permalink: test-utils-ko-KR.html
prev: two-way-binding-helpers-ko-KR.html
next: clone-with-props-ko-KR.html
---
`React.addons.TestUtils`는 선택한 테스트 프레임워크(React는 [Jest](http://facebook.github.io/jest/)를 사용)에서 React 컴포넌트를 테스트하기 쉽게 합니다.
### Simulate
```javascript
Simulate.{eventName}(DOMElement element, object eventData)
```
DOM 노드에 이벤트 디스패치하는 것을 시뮬레이트합니다. 선택적으로 `eventData`를 통해 이벤트 데이터도 처리할 수 있습니다. **아마 `ReactTestUtils`에서 가장 유용한 유틸리티일 것 입니다.**
사용 예:
```javascript
var node = React.findDOMNode(this.refs.input);
React.addons.TestUtils.Simulate.click(node);
React.addons.TestUtils.Simulate.change(node, {target: {value: 'Hello, world'}});
React.addons.TestUtils.Simulate.keyDown(node, {key: "Enter"});
```
`Simulate`에는 React가 이해하는 모든 이벤트에 대해 메소드가 있습니다.
### renderIntoDocument
```javascript
ReactComponent renderIntoDocument(ReactElement instance)
```
문서의 detach된 DOM 노드에 컴포넌트를 렌더합니다. **이 기능은 DOM을 필요로 합니다.**
### mockComponent
```javascript
object mockComponent(function componentClass, string? mockTagName)
```
목 컴포넌트 모듈을 이 메소드에 넘겨 더미 React 컴포넌트로 사용할 수 있도록 합니다. 이 더미는 유용한 메소드와 함께 사용해 기능을 보강할 수 있습니다. 일반적인 렌더링과는 다르게, 컴포넌트는 제공된 자식을 포함하는 평범한 `<div>`가 됩니다. (`mockTagName`을 통해 div가 아닌 다른 태그를 지정해 줄 수도 있습니다.)
### isElement
```javascript
boolean isElement(ReactElement element)
```
`element`가 ReactElement면 true를 리턴합니다.
### isElementOfType
```javascript
boolean isElementOfType(ReactElement element, function componentClass)
```
`element`가 React `componentClass` 타입인 ReactElement면 true를 리턴합니다.
### isDOMComponent
```javascript
boolean isDOMComponent(ReactComponent instance)
```
`instance`가 (`<div>``<span>`같은) DOM 컴포넌트면 true를 리턴합니다.
### isCompositeComponent
```javascript
boolean isCompositeComponent(ReactComponent instance)`
```
`instance`가 (`React.createClass()`로 생성된) 복합 컴포넌트면 true를 리턴합니다.
### isCompositeComponentWithType
```javascript
boolean isCompositeComponentWithType(ReactComponent instance, function componentClass)
```
`instance`가 (`React.createClass()`로 생성된) 복합 컴포넌트고 React `componentClass` 타입이면 true를 리턴합니다.
### findAllInRenderedTree
```javascript
array findAllInRenderedTree(ReactComponent tree, function test)
```
`tree`안의 모든 컴포넌트에서 `test(component)`가 true인 모든 컴포넌트를 모읍니다. 이것만으로는 그렇게 유용하지 않습니다만, 다른 테스트 유틸와 같이 사용합니다.
### scryRenderedDOMComponentsWithClass
```javascript
array scryRenderedDOMComponentsWithClass(ReactComponent tree, string className)
```
렌더된 트리의 모든 컴포넌트 인스턴스 중에서 클래스 이름이 `className`인 DOM 컴포넌트들을 찾습니다.
### findRenderedDOMComponentWithClass
```javascript
ReactComponent findRenderedDOMComponentWithClass(ReactComponent tree, string className)
```
`scryRenderedDOMComponentsWithClass()`와 비슷하지만 하나의 결과만 기대될 때 사용합니다. 하나의 결과를 리턴하거나 한개 이상의 결과가 나온 경우에는 예외를 던집니다.
### scryRenderedDOMComponentsWithTag
```javascript
array scryRenderedDOMComponentsWithTag(ReactComponent tree, string tagName)
```
렌더된 트리의 모든 컴포넌트 인스턴스중에서 태그 이름이 `tagName`인 DOM 컴포넌트들을 찾습니다.
### findRenderedDOMComponentWithTag
```javascript
ReactComponent findRenderedDOMComponentWithTag(ReactComponent tree, string tagName)
```
`scryRenderedDOMComponentsWithTag()`와 비슷하지만 하나의 결과만 기대될 때 사용합니다. 하나의 결과를 리턴하거나 한개 이상의 결과가 나온 경우에는 예외를 던집니다.
### scryRenderedComponentsWithType
```javascript
array scryRenderedComponentsWithType(ReactComponent tree, function componentClass)
```
타입이 `componentClass`인 모든 컴포넌트 인스턴스를 찾습니다.
### findRenderedComponentWithType
```javascript
ReactComponent findRenderedComponentWithType(ReactComponent tree, function componentClass)
```
`scryRenderedComponentsWithType()`와 비슷하지만 하나의 결과만 기대될 때 사용합니다. 하나의 결과를 리턴하거나 한개 이상의 결과가 나온 경우에는 예외를 던집니다.
## 얕은 렌더링
얕은 렌더링은 "한 단계 깊이의" 컴포넌트를 렌더할 수 있는 실험적인 기능입니다. 자식 컴포넌트가 인스턴스화 되거나 렌더되는 등의 동작에 대한 걱정 없이 렌더 메소드가 반환하는 것만 검증합니다. 이 기능은 DOM이 필요하지 않습니다.
```javascript
ReactShallowRenderer createRenderer()
```
테스트에서 얕은 렌더러를 생성하고자 할때 호출합니다. 이를 이벤트와 업데이트에 스스로 반응하는 컴포넌트를 렌더하기 위한 "장소"라고 생각할 수 있습니다.
```javascript
shallowRenderer.render(ReactElement element)
```
`React.render`와 유사합니다.
```javascript
ReactComponent shallowRenderer.getRenderOutput()
```
렌더가 호출 된 후, 얕게 렌더된 결과물을 반환합니다. 그 후엔 결과물에 대한 검증을 시작할 수 있습니다. 예를 들어 컴포넌트의 렌더 메소드가 다음을 반환한다면:
```javascript
<div>
<span className="heading">Title</span>
<Subcomponent foo="bar" />
</div>
```
그 후에는 검증할 수 있습니다:
```javascript
result = renderer.getRenderOutput();
expect(result.type).toBe('div');
expect(result.props.children).toEqual([
<span className="heading">Title</span>,
<Subcomponent foo="bar" />
]);
```
현재 얕은 테스트는 refs를 지원하지 않는 등 몇가지 제약사항이 있습니다. 우리는 이 기능을 빠르게 먼저 배포하고 React 커뮤니티의 피드백을 받아 나아갈 방향을 찾고자 합니다.

View File

@@ -30,7 +30,7 @@ React.addons.TestUtils.Simulate.keyDown(node, {key: "Enter"});
### renderIntoDocument
```javascript
ReactComponent renderIntoDocument(ReactComponent instance)
ReactComponent renderIntoDocument(ReactElement instance)
```
Render a component into a detached DOM node in the document. **This function requires a DOM.**
@@ -175,7 +175,7 @@ Then you can assert:
result = renderer.getRenderOutput();
expect(result.type).toBe('div');
expect(result.props.children).toEqual([
<span className="heading">Title</span>
<span className="heading">Title</span>,
<Subcomponent foo="bar" />
]);
```

View File

@@ -0,0 +1,23 @@
---
id: clone-with-props-ko-KR
title: ReactElement 클론하기
permalink: clone-with-props-ko-KR.html
prev: test-utils-ko-KR.html
next: create-fragment-ko-KR.html
---
드문 경우긴 하지만 엘리먼트에서 소유하지 않은 엘리먼트의 props를 변경하고 싶을 때가 있습니다 (`this.props.children`로 전달된 엘리먼트의 `className` 변경 같은 경우). 아니면 전달된 엘리먼트의 복사본 여러 개를 만들고 싶을 수도 있습니다. 이는 `cloneWithProps()`로 할 수 있습니다.
#### `ReactElement React.addons.cloneWithProps(ReactElement element, object? extraProps)`
`element`를 얕게 복사하고 `extraProps`로 넘긴 props를 머지합니다. `className``style` props는 지능적인 방법으로 머지됩니다.
> 주의:
>
> `cloneWithProps`는 `key`를 클론된 엘리먼트에 전달하지 않습니다. 키를 보존하고 싶으시면, `extraProps` 객체에 넣으세요.
>
> ```js
> var clonedElement = cloneWithProps(originalElement, { key : originalElement.key });
> ```
>
> 비슷하게 `ref`도 유지되지 않습니다.

View File

@@ -6,7 +6,7 @@ prev: test-utils.html
next: create-fragment.html
---
In rare situations a element may want to change the props of a element that it doesn't own (like changing the `className` of a element passed as `this.props.children`). Other times it may want to make multiple copies of a element passed to it. `cloneWithProps()` makes this possible.
In rare situations an element may want to change the props of an element that it doesn't own (like changing the `className` of an element passed as `this.props.children`). Other times it may want to make multiple copies of an element passed to it. `cloneWithProps()` makes this possible.
#### `ReactElement React.addons.cloneWithProps(ReactElement element, object? extraProps)`

View File

@@ -0,0 +1,73 @@
---
id: create-fragment-ko-KR
title: 키가 할당된 프래그먼트
permalink: create-fragment-ko-KR.html
prev: clone-with-props-ko-KR.html
next: update-ko-KR.html
---
대부분의 경우는 `key` prop으로 `render`에서 반환된 엘리먼트에 키를 명시할 수 있습니다. 하지만 말썽을 부리는 경우가 한가지 있습니다: 재정렬을 할 두개의 자식 집합을 가지고 있는 경우, 감싸는 엘리먼트 없이 각각의 집합에 키를 부여하는 것은 불가능 합니다.
이 말은, 만약 다음과 같은 컴포넌트가 있다면:
```js
var Swapper = React.createClass({
propTypes: {
// `leftChildren`과 `rightChildren`은 문자열, 엘리먼트, 배열 혹은 다른 무언가 일 수 있음.
leftChildren: React.PropTypes.node,
rightChildren: React.PropTypes.node,
swapped: React.PropTypes.bool
}
render: function() {
var children;
if (this.props.swapped) {
children = [this.props.rightChildren, this.props.leftChildren];
} else {
children = [this.props.leftChildren, this.props.rightChildren];
}
return <div>{children}</div>;
}
});
```
`swapped` prop을 변경할 경우 자식은 마운트 해제되거나 다시 마운트 될 수 있습니다. 두 자식 집합에 키가 할당되지 않았기 때문입니다.
이 문제를 해결하기 위해서 `React.addons.createFragment`를 사용해 자식 집합에 키를 부여할 수 있습니다.
#### `ReactFragment React.addons.createFragment(object children)`
배열을 만드는 대신에 다음과 같이 해볼 수 있습니다:
```js
if (this.props.swapped) {
children = React.addons.createFragment({
right: this.props.rightChildren,
left: this.props.leftChildren
});
} else {
children = React.addons.createFragment({
left: this.props.leftChildren,
right: this.props.rightChildren
});
}
```
전달된 객체의 키(`left`, `right`)는 모든 자식 집합의 키로 사용됩니다. 그리고 객체에서 키들의 순서는 렌더된 자식들의 순서를 결정하는데 사용됩니다. 이러한 변경으로 두 자식 집합은 언마운팅하지 않고도 DOM에서 적절하게 재정렬 됩니다.
`createFragment`의 반환값은 불명확한 객체로 취급되어야 합니다; `React.Children` 헬퍼를 사용해 프래그먼트를 순환할 수 있지만 직접 접근해서는 안됩니다. 명세에는 없지만 모든 주요 브라우저와 VM들에서 JavaScript 엔진이 숫자가 아닌 키에 대해서도 객체 목록 순서를 보존한다는 점을 주의하세요.
> **주의:**
>
> 미래에 `createFragment`는 대략 다음과 같은 API로 교체될 것입니다
>
> ```js
> return (
> <div>
> <x:frag key="right">{this.props.rightChildren}</x:frag>,
> <x:frag key="left">{this.props.leftChildren}</x:frag>
> </div>
> );
> ```
>
> JSX에서 엘리먼트로 감싸지 않고도 key를 바로 선언할 수 있게 될 것입니다.

View File

@@ -0,0 +1,101 @@
---
id: update-ko-KR
title: 불변성 헬퍼들
permalink: update-ko-KR.html
prev: create-fragment-ko-KR.html
next: pure-render-mixin-ko-KR.html
---
React에서는 mutation을 포함해 어떤 데이터 관리 방식도 사용하실 수 있습니다. 하지만 애플리케이션의 성능이 중요한 부분에서 불변의(immutable) 데이터를 사용할 수 있다면, 쉽게 빠른 `shouldComponentUpdate()` 메소드를 구현해 애플리케이션의 속도를 크게 향상시킬 수 있습니다.
JavaScript에서 불변성의 데이터를 다루는 것은 [Clojure](http://clojure.org/)같이 그것을 위해 디자인된 언어로 다루는 것보다는 어렵습니다. 하지만, React는 간단한 불변성 헬퍼를 제공합니다. `update()`는 이런 종류의 데이터를 근본적인 변화 *없이* 쉽게 다루도록 해줍니다.
## 주요 아이디어
만약 데이터를 이렇게 변화시킨다면:
```js
myData.x.y.z = 7;
// or...
myData.a.b.push(9);
```
이전의 카피가 덮어씌워진다면 어떤 자료가 바뀌었는지 알 방도가 없습니다. 대신에, `myData`의 새로운 카피를 만들고 오직 변화가 필요한 부분만 바꿀 필요가 있습니다. 그 다음 `shouldComponentUpdate()` 에서 `myData`의 이전 카피와 새로운 카피를 `===` 연산자를 사용하여 비교할 수 있습니다.
```js
var newData = deepCopy(myData);
newData.x.y.z = 7;
newData.a.b.push(9);
```
하지만 깊은 복사는 비싸고, 가끔은 불가능하기도 합니다. 변화가 필요한 객체만 복제하고, 변화가 없는 객체는 다시 사용하는 방법으로만 비용을 줄일 수 있습니다. 안타깝지만 오늘날의 JavaScript에서는 그 방법이 성가실 수 있습니다:
```js
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)})
});
```
이것은 꽤 성능이 좋긴 하지만 (`log n`개의 객체만 얕은 복사하고, 나머지는 재사용하기 때문에), 일일히 쓰기엔 큰 고통이 따릅니다. 이 반복들을 보세요! 이건 짜증날 뿐만 아니라 버그들을 야기할수도 있습니다.
`update()`는 이런 패턴 속에서 코드를 더 쉽게 쓸 수 있도록 편의 문법을 제공합니다. 코드는 이렇습니다:
```js
var newData = React.addons.update(myData, {
x: {y: {z: {$set: 7}}},
a: {b: {$push: [9]}}
});
```
([MongoDB 쿼리 언어](http://docs.mongodb.org/manual/core/crud-introduction/#query)에서 영감을 받은) 이 문법에 익숙해지기에는 시간이 조금 걸리긴 하지만, 쓸모 없는 반복이 없고 정적분석이 가능할 뿐더러 변할 수 있는(mutative) 버전보다 더 많은 타이핑이 필요하지도 않습니다.
`$`가 앞에 붙어있는 키들은 *커맨드* 라고 불립니다. "변하는" 자료 구조는 *타겟* 이라고 불립니다.
## 사용가능한 커맨드들
* `{$push: array}` 모든 아이템들을 타겟에 있는 `array``push()`합니다.
* `{$unshift: array}` 타겟속 `array`에 있는 모든 아이템들을 `unshift()`합니다.
* `{$splice: array of arrays}` `arrays` 안의 각 아이템들이 `splice()`를 주어진 인자들을 사용해 호출하게 합니다.
* `{$set: any}` 타겟 전체를 대체합니다.
* `{$merge: object}` 타겟과 `object`의 키들을 병합합니다.
* `{$apply: function}` 는 지금 값을 함수에 전달하고 새로운 리턴 값으로 업데이트합니다.
## 예제
### 간단한 push
```js
var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
```
`initialArray` 은 여전히 `[1, 2, 3]` 입니다.
### 중첩된 컬렉션
```js
var collection = [1, 2, {a: [12, 17, 15]}];
var newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}});
// => [1, 2, {a: [12, 13, 14, 15]}]
```
이것은 `collection`의 인덱스 `2`의 키 `a`에 접근해, 인덱스 `1`에 있는 한 아이템을 접합(splice)해서(`17`를 제거하고) `13`, `14`를 추가합니다.
### 현재 상태에 의거해 값을 업데이트
```js
var obj = {a: 5, b: 3};
var newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}});
// => {a: 5, b: 6}
// 위의 것과 같은 동작을 합니다만, 깊게 중첩된 컬렉션들에서는 더 장황해 집니다.
var newObj2 = update(obj, {b: {$set: obj.b * 2}});
```
### (얕은) 합병
```js
var obj = {a: 5, b: 3};
var newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7}
```

View File

@@ -0,0 +1,30 @@
---
id: pure-render-mixin-ko-KR
title: PureRenderMixin
permalink: pure-render-mixin-ko-KR.html
prev: update-ko-KR.html
next: perf-ko-KR.html
---
React 컴포넌트의 렌더 함수가 "pure"하다면 (다른 말로, props나 state에 같은 값이 주어질 때 같은 결과를 렌더한다면) 몇몇 경우엔 이 믹스인을 사용하여 성능을 향상시킬 수 있습니다.
예제:
```js
var PureRenderMixin = require('react/addons').addons.PureRenderMixin;
React.createClass({
mixins: [PureRenderMixin],
render: function() {
return <div className={this.props.className}>foo</div>;
}
});
```
내부적으로 믹스인은 현재의 props와 state를 다음 값과 비교하여 같다면 `false`를 반환하도록 [shouldComponentUpdate](/react/docs/component-specs-ko-KR.html#updating-shouldcomponentupdate)를 구현합니다.
> 주의:
>
> 여기서는 객체에 대한 얕은(shallow) 비교만 합니다. 복잡한 데이터 구조를 가진 경우에는 깊은 부분의 차이에 대해 잘못된 false를 반환 할 수도 있습니다. 간단한 props와 state를 사용하는 컴포넌트에만 적용하거나 깊은 데이터 구조가 변경 되었을때는 `forceUpdate()`를 사용하세요. 아니면 중첩 데이터의 비교를 빠르고 용이하게 하기 위해 [immutable 객체](http://facebook.github.io/immutable-js/)의 도입을 고려해보세요.
>
> 또, `shouldComponentUpdate`는 컴포넌트 서브트리의 업데이트를 건너뜁니다. 모든 자식 컴포넌트들도 "pure"한지 확인하세요.

View File

@@ -0,0 +1,72 @@
---
id: perf-ko-KR
title: 성능 도구
permalink: perf-ko-KR.html
prev: pure-render-mixin-ko-KR.html
next: advanced-performance-ko-KR.html
---
React는 보통 처음에는 꽤 빠릅니다. 하지만 모든 성능을 짜내야 하는 상황일 때를 위해, React는 [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate) 훅을 제공해 React의 diff 알고리즘을 위한 최적화 힌트를 추가할 수 있습니다.
덧붙여 앱의 전반적인 성능의 개요도 제공합니다. ReactPerf는 프로파일링 도구로 정확히 어디에 훅이 필요한지 알려줍니다.
> 주의:
>
> React의 개발 빌드는 제공되는 추가 기능으로 인해 프로덕션 빌드보다 느립니다. 추가 기능에는 React의 친절한 콘솔 경고같은 것이 있습니다.(이는 프로덕션 빌드에서는 제거 됩니다) 따라서, 프로파일러는 앱의 _상대적으로_ 비싼 부분만 표시하도록 합니다.
## 일반 API
여기에서 설명하는 `Perf` 객체는 `react-with-addons.js`를 사용해 개발 모드에서 빌드될 때 `React.addons.Perf`로 노출됩니다.
### `Perf.start()`와 `Perf.stop()`
측정을 시작/정지합니다. 그 사이의 React 연산은 밑에 있는 분석을 하기위해 기록됩니다. 미미한 양의 연산은 무시됩니다.
### `Perf.printInclusive(measurements)`
전 수행 시간을 출력합니다. 인자가 넘겨지지 않으면, 기본값은 지난 기록부터의 모든 측정이 됩니다. 이 출력은 밑에 있는 것처럼 콘솔에서 깔끔한 테이블로 그려집니다.
![](/react/img/docs/perf-inclusive.png)
### `Perf.printExclusive(measurements)`
컴포넌트를 마운트하는 시간을 포함하지 않은 "exclusive" 시간입니다. 여기에는 props 연산, `getInitialState`, `componentWillMount` 호출, `componentDidMount`등이 포함됩니다.
![](/react/img/docs/perf-exclusive.png)
### `Perf.printWasted(measurements)`
**프로파일러에서 가장 유용한 부분입니다**.
렌더가 같아서, DOM을 변경(touch)하지 않는 경우같은 실제로는 아무것도 렌더하지 않는 컴포넌트가 사용하는 "낭비되는" 시간을 출력합니다.
![](/react/img/docs/perf-wasted.png)
### `Perf.printDOM(measurements)`
"set innerHTML"이나 "remove"같은 기저의 DOM 조작을 출력합니다.
![](/react/img/docs/perf-dom.png)
## 고급 API
위의 출력 메소드에 `Perf.getLastMeasurements()`를 사용해 결과를 이쁘게 출력합니다.
### `Perf.getLastMeasurements()`
마지막 start-stop 세션에서 측정들의 배열을 가져옵니다. 이 배열은 이런 객체들을 가지고 있습니다.
```js
{
// 용어 "inclusive"와 "exclusive"는 위에서 설명했음
"exclusive": {},
// '.0.0'는 노드의 React ID
"inclusive": {".0.0": 0.0670000008540228, ".0": 0.3259999939473346},
"render": {".0": 0.036999990697950125, ".0.0": 0.010000003385357559},
// 인스턴스의 수
"counts": {".0": 1, ".0.0": 1},
// DOM 변경(touch)
"writes": {},
// 추가 디버깅 정보
"displayNames": {
".0": {"current": "App", "owner": "<root>"},
".0.0": {"current": "Box", "owner": "App"}
},
"totalTime": 0.48499999684281647
}
```

View File

@@ -0,0 +1,205 @@
---
id: advanced-performance-ko-KR
title: 성능 심화
permalink: advanced-performance-ko-KR.html
prev: perf-ko-KR.html
---
React를 도입하려 할 때 많은 사람이 묻는 첫 번째 질문은 React를 사용하지 않을 때처럼 애플리케이션이 빠르고 반응성도 좋을 것이냐는 것입니다. 모든 상태변화에 대해 컴포넌트의 하위 트리를 전부 다시 렌더링하는 아이디어에 대해 사람들은 이 프로세스가 성능에 부정적인 영향을 줄 것으로 생각하지만, React는 여러 가지 영리한 방법을 통해 UI를 업데이트하는데 필요한 비싼 DOM 조작을 최소화합니다.
## DOM 조정 회피
React는 브라우저에서 렌더된 DOM 하위 트리의 서술자 개념인 *가상의 DOM*을 사용합니다. 이 병렬적인 서술체는 React가 DOM 노드를 생성하거나 이미 존재하는 DOM 노드에 접근하는 것(JavaScript 객체를 조작하는 것보다 느리죠)을 피하게 해 줍니다. 컴포넌트의 props나 state가 변경되면 React는 새로운 가상의 DOM을 구성해 이전의 것과 비교해서 실제 DOM 업데이트가 필요한지 결정합니다. 가능한 적게 변화를 적용하기 위해, React는 둘이 다를 경우에만 DOM을 [조정](/react/docs/reconciliation-ko-KR.html)할 것입니다.
이에 더해, React는 컴포넌트 생명주기 함수인 `shouldComponentUpdate`를 제공합니다. 이는 다시 렌더링하는 프로세스(가상 DOM 비교와 어쩌면 일어날 DOM 조정)가 일어나기 직전에 일어나며 개발자가 프로세스를 중단할 수 있게 합니다. 이 함수의 기본구현은 `true`를 반환해 React가 업데이트를 수행하도록 합니다.
```javascript
shouldComponentUpdate: function(nextProps, nextState) {
return true;
}
```
React가 이 함수를 자주 호출한다는 것을 명심하십시오. 따라서 구현체는 빨라야 합니다.
대화 스레드가 여럿 돌고 있는 메시지처리 애플리케이션을 생각해 봅시다. 오직 하나의 스레드만이 변경되었다고 가정해 보죠. `ChatThread``shouldComponentUpdate`를 구현했다면 React는 다른 스레드의 렌더링 프로세스를 건너뛸 수 있습니다.
```javascript
shouldComponentUpdate: function(nextProps, nextState) {
// TODO: 현재의 대화 스레드가 이전의 것과 다른지 아닌지를 반환한다
}
```
정리하자면, React는 사용자가 `shouldComponentUpdate`를 사용해 렌더링 프로세스를 중단하고 가상의 DOM과 비교해 업데이트 여부를 결정해서 DOM의 하위 트리를 조정하는 비싼 DOM 조작을 피하도록 합니다.
## shouldComponentUpdate 실전
다음은 컴포넌트의 하위 트리입니다. 각각은 `shouldComponentUpdate`의 반환값(SCU)과 가상의 DOM과의 동일성(vDOMEq)을 표시합니다. 마지막으로, 원의 색은 컴포넌트가 조정되었는지를 표시합니다.
<figure><img src="/react/img/docs/should-component-update.png" /></figure>
위의 예시에서, C2를 루트로 하는 하위 트리에 대해 `shouldComponentUpdate``false`를 반환했기 때문에 React는 새로운 가상의 DOM을 만들 필요가 없습니다. 따라서 DOM을 조정할 필요도 없습니다. React가 C4와 C5에는 `shouldComponentUpdate`를 요청하지도 않은 것을 확인하세요.
C1과 C3의 `shouldComponentUpdate``true`를 반환했기 때문에 React는 하위 노드로 내려가 그들을 확인합니다. C6는 `true`를 반환했네요; 이는 가상의 DOM과 같지 않기 때문에 DOM의 조정이 일어났습니다. 마지막으로 흥미로운 사례는 C8입니다. React가 이 노드를 위해 가상의 DOM을 작동했지만, 노드가 이전의 것과 일치했기 때문에 DOM의 조정을 일어나지 않았습니다.
React가 C6에만 DOM 변경을 수행한 것을 확인하세요. 이는 필연적이었습니다. C8의 경우는 가상의 DOM과 비교를 해 제외되었고, C2의 하위 트리와 C7은 `shouldComponentUpdate` 단계에서 제외되어 가상의 DOM은 구동조차 되지 않았습니다.
자 그럼, 어떻게 `shouldComponentUpdate`를 구현해야 할까요? 문자열 값을 렌더하는 컴포넌트를 생각해보죠.
```javascript
React.createClass({
propTypes: {
value: React.PropTypes.string.isRequired
},
render: function() {
return <div>this.props.value</div>;
}
});
```
다음과 같이 간단히 `shouldComponentUpdate`를 구현해 볼 수 있습니다:
```javascript
shouldComponentUpdate: function(nextProps, nextState) {
return this.props.value !== nextProps.value;
}
```
여기까지는 좋습니다. 간단한 props/state 구조를 다루기는 쉽습니다. 단순한 등식비교 구현을 일반화하고 이를 컴포넌트에 혼합할 수도 있습니다. 사실, React는 이미 그런 구현을 제공합니다: [PureRenderMixin](/react/docs/pure-render-mixin-ko-KR.html).
하지만 만약 컴포넌트의 props나 state가 가변적인 데이터 구조로 되어 있다면 어떨까요? 컴포넌트의 prop으로 `'bar'`같은 문자열 대신에 `{ foo: 'bar' }`처럼 문자열을 포함한 JavaScript 객체를 전달받는다고 해봅시다.
```javascript
React.createClass({
propTypes: {
value: React.PropTypes.object.isRequired
},
render: function() {
return <div>this.props.value.foo</div>;
}
});
```
전에 구현했던 `shouldComponentUpdate`는 언제나 예상대로 작동하지 않을 것입니다:
```javascript
// this.props.value가 { foo: 'bar' }라고 가정합니다
// nextProps.value도 { foo: 'bar' }라고 가정하지만,
// 이 참조는 this.props.value와 다른 것입니다
this.props.value !== nextProps.value; // true
```
문제는 prop이 실제로 변경되지 않았을 때도 `shouldComponentUpdate``true`를 반환할 거라는 겁니다. 이를 해결하기 위한 대안으로 아래와 같이 구현해 볼 수 있습니다:
```javascript
shouldComponentUpdate: function(nextProps, nextState) {
return this.props.value.foo !== nextProps.value.foo;
}
```
기본적으로, 우리는 변경을 정확히 추적하기 위해서 깊은 비교를 해야 했습니다. 이 방법은 성능 면에서 제법 비싸고 각각의 모델마다 다른 깊은 등식 코드를 작성해야 하므로 확장이 힘들어 집니다. 심지어 객체 참조를 신중히 관리하지 않는다면 작동하지도 않을 수 있습니다. 컴포넌트가 부모에 의해 다뤄지는 경우를 살펴보죠:
```javascript
React.createClass({
getInitialState: function() {
return { value: { foo: 'bar' } };
},
onClick: function() {
var value = this.state.value;
value.foo += 'bar'; // 안티패턴 입니다!
this.setState({ value: value });
},
render: function() {
return (
<div>
<InnerComponent value={this.state.value} />
<a onClick={this.onClick}>클릭하세요</a>
</div>
);
}
});
```
처음엔 내부 컴포넌트(`<InnerComponent />`)가 `{ foo: 'bar' }`를 value prop으로 가진 채 렌더될 것입니다. 사용자가 앵커(`<a>`)를 클릭한다면 부모 컴포넌트의 state는 `{ value: { foo: 'barbar' } }`로 업데이트되고, 내부 컴포넌트 또한 `{ foo: 'barbar' }`를 새로운 value prop으로 전달받아 다시 렌더링 되는 프로세스가 일어날 것입니다.
이 문제는 부모와 내부 컴포넌트가 같은 객체에 대한 참조를 공유하기 때문에 발생합니다. `onClick` 함수의 두 번째 줄에서 객체에 대한 변경이 일어날 때, 내부 컴포넌트의 prop도 변경될 것입니다. 따라서 다시 렌더링 되는 프로세스가 시작될 때 `shouldComponentUpdate`가 호출되고 `this.props.value.foo``nextProps.value.foo`와 같게 됩니다. 실제로 `this.props.value``nextProps.value`와 같은 객체이기 때문입니다.
그에따라 prop의 변경을 놓치게 되어 다시 렌더링하는 프로세스가 중단되고, UI는 `'bar'`에서 `'barbar'`로 업데이트되지 않습니다.
## 구원자 Immutable-js
[Immutable-js](https://github.com/facebook/immutable-js)는 Lee Byron이 만들고 Facebook이 오픈소스화 한 Javascript 컬렉션 라이브러리입니다. 이는 *구조의 공유(structural sharing)*를 통해 *불변의 영속적인(immutable persistent)* 컬렉션을 제공합니다. 이러한 속성이 무엇을 의미하는지 살펴보죠:
* *불변성(Immutable)*: 컬렉션이 한번 생성되면, 이 후 다른 시점에 변경될 수 없습니다.
* *영속성(Persistent)*: 새로운 컬렉션이 이전의 컬렉션이나 셋(set) 같은 뮤테이션(mutation)에서 생성될 수 있습니다. 기존의 컬렉션은 새로운 컬렉션이 생성된 후에도 여전히 유효합니다.
* *구조의 공유(Structural Sharing)*: 새로운 컬렉션은 가능한 한 원래의 컬렉션과 같은 구조를 사용해 생성됩니다. 공간 효율성과 적절한 성능을 위해 복사를 최소화합니다.
불변성은 변경의 추적을 비용을 줄여줍니다; 변경은 항상 새로운 객체에만 발생하기 때문에 객체에 대한 참조가 변경될 때만 확인하면 됩니다. 예를 들어 일반적인 JavaScript 코드에서는:
```javascript
var x = { foo: "bar" };
var y = x;
y.foo = "baz";
x === y; // true
```
`y`가 수정되더라도 여전히 같은 객체인 `x`를 참조하고 있기 때문에, 이 비교는 `true`를 반환합니다. 하지만 이 코드를 immutable-js를 사용해 다음과 같이 작성할 수 있습니다:
```javascript
var SomeRecord = Immutable.Record({ foo: null });
var x = new SomeRecord({ foo: 'bar' });
var y = x.set('foo', 'baz');
x === y; // false
```
이 경우, `x`가 변경되면 새로운 참조가 반환되기 때문에, 우리는 안전하게 `x`가 변경되었을 것으로 추정할 수 있습니다.
변경을 탐지할 수 있는 또 다른 방법은 세터(setter)에 의해 설정된 플래그를 더티 체킹(dirty checking)하는 것입니다. 이 방식의 문제는 당신이 세터를 사용할 뿐만 아니라 수많은 추가 코드를 작성하거나 어떻게든 클래스들을 인스트루먼트(instrument) 하도록 강요한다는 것입니다. 혹은 변경(mutations) 직전에 객체를 깊은 복사(deep copy) 한 뒤 깊은 비교(deep compare)를 수행해 변경 여부를 판단할 수 있습니다. 이 방식의 문제점은 deepCopy와 deepCompare 둘 다 비용이 많이 드는 연산이라는 것입니다.
그래서 Immutable 자료구조는 `shouldComponentUpdate`의 구현에 필요한 객체의 변경사항을 추적할 수 있는 덜 자세하지만 저렴한 방법을 제공합니다. 그에 따라 immutable-js가 제공하는 추상화를 사용해 props와 state 어트리뷰트를 모델링한다면, `PureRenderMixin`을 사용해 성능을 향상할 수 있습니다.
## Immutable-js와 Flux
[Flux](http://facebook.github.io/flux/)를 사용한다면 immutable-js를 사용해 stores를 작성해야 합니다. [전체 API](http://facebook.github.io/immutable-js/docs/#/)를 살펴보세요.
Immutable 자료구조를 이용해 스레드를 모델링하는 예제를 살펴봅시다. 먼저 모델링하려는 엔티티마다 `Record`를 정의해야 합니다. Record는 특정 필드들의 값을 유지하기 위한 불변의 컨테이너입니다:
```javascript
var User = Immutable.Record({
id: undefined,
name: undefined,
email: undefined
});
var Message = Immutable.Record({
timestamp: new Date(),
sender: undefined,
text: ''
});
```
`Record` 함수는 필드별로 기본값이 선언된 객체에 대한 정의를 넘겨받습니다.
메시지 store는 두 개의 List를 통해 users와 messages를 추적할 수 있습니다:
```javascript
this.users = Immutable.List();
this.messages = Immutable.List();
```
각각의 *페이로드* 타입을 처리하는 기능을 구현하는 것은 꽤 간단합니다. 예를 들면, store가 새 메시지를 나타내는 페이로드를 확인할 때 레코드를 새로 생성하고 메시지 리스트에 추가할 수 있습니다.
```javascript
this.messages = this.messages.push(new Message({
timestamp: payload.timestamp,
sender: payload.sender,
text: payload.text
});
```
자료구조가 불변이기 때문에 push 함수의 결과를 this.messages에 할당할 필요가 있으니 주의하세요.
React 측에서는, 컴포넌트의 state를 보존하기 위해 immutable-js 자료구조를 사용한다면, 모든 컴포넌트에 `PureRenderMixin`을 혼합해 다시 렌더링하는 프로세스를 중단할 수 있습니다.

View File

@@ -11,7 +11,7 @@ One of the first questions people ask when considering React for a project is wh
React makes use of a *virtual DOM*, which is a descriptor of a DOM subtree rendered in the browser. This parallel representation allows React to avoid creating DOM nodes and accessing existing ones, which is slower than operations on JavaScript objects. When a component's props or state change, React decides whether an actual DOM update is necessary by constructing a new virtual DOM and comparing it to the old one. Only in the case they are not equal, will React [reconcile](http://facebook.github.io/react/docs/reconciliation.html) the DOM, applying as few mutations as possible.
On top of this, React provides a component lifecycle function, `shouldComponentUpdate`, which is triggered before the re-rendering process starts, giving the developer the ability to short circuit this process. The default implementation of this function returns `true`, leaving React to perform the update:
On top of this, React provides a component lifecycle function, `shouldComponentUpdate`, which is triggered before the re-rendering process starts (virtual DOM comparison and possible eventual DOM reconciliation), giving the developer the ability to short circuit this process. The default implementation of this function returns `true`, leaving React to perform the update:
```javascript
shouldComponentUpdate: function(nextProps, nextState) {
@@ -38,7 +38,7 @@ Here's a subtree of components. For each one is indicated what `shouldComponentU
<figure><img src="/react/img/docs/should-component-update.png" /></figure>
In the example above, since `shouldComponentUpdate` returned `false` for the subtree rooted at C2, React had no need to generate the new virtual DOM, and therefore, it neither needed to reconcile the DOM. Note that React didn't even had to invoke `shouldComponentUpdate` on C4 and C5.
In the example above, since `shouldComponentUpdate` returned `false` for the subtree rooted at C2, React had no need to generate the new virtual DOM, and therefore, it neither needed to reconcile the DOM. Note that React didn't even have to invoke `shouldComponentUpdate` on C4 and C5.
For C1 and C3 `shouldComponentUpdate` returned `true`, so React had to go down to the leaves and check them. For C6 it returned `true`; since the virtual DOMs weren't equivalent it had to reconcile the DOM.
The last interesting case is C8. For this node React had to compute the virtual DOM, but since it was equal to the old one, it didn't have to reconcile it's DOM.
@@ -49,7 +49,7 @@ So, how should we implement `shouldComponentUpdate`? Say that you have a compone
```javascript
React.createClass({
propsTypes: {
propTypes: {
value: React.PropTypes.string.isRequired
},
@@ -73,7 +73,7 @@ But what if your components' props or state are mutable data structures?. Say th
```javascript
React.createClass({
propsTypes: {
propTypes: {
value: React.PropTypes.object.isRequired
},

View File

@@ -0,0 +1,9 @@
---
id: complementary-tools-ko-KR
title: 상호 보완적인 도구들
permalink: complementary-tools-ko-KR.html
prev: videos-ko-KR.html
next: examples-ko-KR.html
---
이 페이지는 이동되었습니다. [GitHub wiki](https://github.com/facebook/react/wiki/Complementary-Tools).

View File

@@ -0,0 +1,19 @@
---
id: conferences-ko-KR
title: 컨퍼런스들
permalink: conferences-ko-KR.html
prev: thinking-in-react-ko-KR.html
next: videos-ko-KR.html
---
### React.js Conf 2015
1월 28일 & 29일
[웹사이트](http://conf.reactjs.com/) - [스케줄](http://conf.reactjs.com/schedule.html) - [비디오들](https://www.youtube.com/playlist?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr)
<iframe width="650" height="315" src="//www.youtube.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
### ReactEurope 2015
7월 2일 & 3일
[웹사이트](http://www.react-europe.org/) - [스케줄](http://www.react-europe.org/#schedule)

View File

@@ -0,0 +1,8 @@
---
id: examples-ko-KR
title: 예제들
permalink: examples-ko-KR.html
prev: complementary-tools-ko-KR.html
---
이 페이지는 이동되었습니다. [GitHub wiki](https://github.com/facebook/react/wiki/Examples).

View File

@@ -0,0 +1,7 @@
---
id: flux-overview-ko-KR
title: Flux 애플리케이션 아키텍쳐
permalink: flux-overview-ko-KR.html
---
이 페이지는 Flux 웹사이트로 이동되었습니다. [거기서 보세요](http://facebook.github.io/flux/docs/overview.html).

View File

@@ -1,6 +1,7 @@
---
id: flux-overview
title: Flux Application Architecture
permalink: flux-overview.html
---
This page has been moved to the Flux website. [View it there](http://facebook.github.io/flux/docs/overview.html).

View File

@@ -0,0 +1,7 @@
---
id: flux-todo-list-ko-KR
title: Flux TodoMVC 튜토리얼
permalink: flux-todo-list-ko-KR.html
---
이 페이지는 Flux 웹사이트로 이동되었습니다. [거기서 보세요](http://facebook.github.io/flux/docs/todo-list.html).

View File

@@ -1,6 +1,7 @@
---
id: flux-todo-list
title: Flux TodoMVC Tutorial
permalink: flux-todo-list.html
---
This page has been moved to the Flux website. [View it there](http://facebook.github.io/flux/docs/todo-list.html).

View File

@@ -0,0 +1,116 @@
---
id: getting-started-ja-JP
title: 始めてみましょう
next: tutorial-ja-JP.html
redirect_from: "docs/index-ja-JP.html"
---
## JSFiddle
React でのハッキングを始めるにあたり、一番簡単なものとして次の JSFiddle で動いている Hello World の例を取り上げます。
* **[React JSFiddle](http://jsfiddle.net/reactjs/69z2wepo/)**
* [React JSFiddle without JSX](http://jsfiddle.net/reactjs/5vjqabv3/)
## スターターキット
始めるためにスターターキットをダウンロードしましょう。
<div class="buttons-unit downloads">
<a href="/react/downloads/react-{{site.react_version}}.zip" class="button">
Download Starter Kit {{site.react_version}}
</a>
</div>
スターターキットのルートディレクトリに `helloworld.html` を作り、次のように書いてみましょう。
```html
<!DOCTYPE html>
<html>
<head>
<script src="build/react.js"></script>
<script src="build/JSXTransformer.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/jsx">
React.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
</script>
</body>
</html>
```
JavaScript の中に書かれた XML シンタックスは JSX と呼ばれるものですJSX の詳しいことについては [JSX syntax](/react/docs/jsx-in-depth.html) を読んでください)。ここでは JSX から vanilla JavaScript への変換をブラウザ内で行わせるため、先程のコードには `<script type="text/jsx">` と書いており、加えて `JSXTransformer.js` を読み込ませています。
### ファイルの分割
React の JSX コードは別ファイルに分離することができます。 次のような `src/helloworld.js` を作ってみましょう。
```javascript
React.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
```
それが終わったら、`helloworld.js` への参照を `helloworld.html` に書き込みましょう。
```html{10}
<script type="text/jsx" src="src/helloworld.js"></script>
```
### オフラインでの変換
まずはコマンドラインツールをインストールしましょう([npm](http://npmjs.org/) が必要です)。
```
npm install -g react-tools
```
インストールが終わったら、先程書いた `src/helloworld.js` ファイルを生の JavaScript に変換してみましょう。
```
jsx --watch src/ build/
```
すると、`src/helloword.js` に変更を加えるごとに `build/helloworld.js` が自動で生成されるようになります。
```javascript{2}
React.render(
React.createElement('h1', null, 'Hello, world!'),
document.getElementById('example')
);
```
最後に HTML ファイルを以下のように書き換えましょう。
```html{6,10}
<!DOCTYPE html>
<html>
<head>
<title>Hello React!</title>
<script src="build/react.js"></script>
<!-- JSXTransformer は必要ありません! -->
</head>
<body>
<div id="example"></div>
<script src="build/helloworld.js"></script>
</body>
</html>
```
## CommonJS を使うには
React を [browserify](http://browserify.org/) や [webpack](http://webpack.github.io/)、または CommonJS 準拠の他のモジュールシステムと一緒に使いたい場合、 [`react` npm package](https://www.npmjs.org/package/react) を使ってみてください。また、`jsx` ビルドツールをパッケージングシステムCommonJS に限らず)に導入することも非常に簡単です。
## 次にすること
[チュートリアル](/react/docs/tutorial.html) や、スターターキットの `examples` ディレクトリに入っている他の例を読んでみてください。
また、[ワークフロー、UIコンポーネント、ルーティング、データマネジメントなど](https://github.com/facebook/react/wiki/Complementary-Tools)の方面で貢献しているコミュニティの wiki もあります。
幸運を祈りますReact へようこそ!

View File

@@ -0,0 +1,116 @@
---
id: getting-started-ko-KR
title: 시작해보기
permalink: getting-started-ko-KR.html
next: tutorial-ko-KR.html
redirect_from: "docs/index-ko-KR.html"
---
## JSFiddle
React를 시작하는 가장 빠른 방법은 다음의 Hello World JSFiddle 예제를 따라 해 보는 것입니다.
* **[React JSFiddle](http://jsfiddle.net/reactjs/69z2wepo/)**
* [React JSFiddle without JSX](http://jsfiddle.net/reactjs/5vjqabv3/)
## 초심자용 키트
초심자용 키트를 내려받아 시작합니다.
<div class="buttons-unit downloads">
<a href="/react/downloads/react-{{site.react_version}}.zip" class="button">
초심자용 키트 내려받기 {{site.react_version}}
</a>
</div>
초심자용 키트의 최상위 디렉터리에 아래의 내용대로 `helloworld.html` 파일을 생성합니다.
```html
<!DOCTYPE html>
<html>
<head>
<script src="build/react.js"></script>
<script src="build/JSXTransformer.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/jsx">
React.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
</script>
</body>
</html>
```
JavaScript 안에 보이는 XML 구문은 JSX라고 합니다; 더 자세한 내용은 [JSX syntax](/react/docs/jsx-in-depth-ko-KR.html)을 확인하세요. 일반적인 JavaScript로 번역하기 위해 `<script type="text/jsx">`를 사용하고 `JSXTransformer.js`를 포함하는 것으로 실제로 브라우저에서 변환작업을 수행합니다.
### 파일의 분리
React JSX 코드는 분리된 파일로 존재할 수 있습니다. 다음 내용으로 `src/helloworld.js`를 생성해보세요.
```javascript
React.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
```
그다음 `helloworld.html`에서 참조합니다:
```html{10}
<script type="text/jsx" src="src/helloworld.js"></script>
```
### 오프라인 변환
먼저 커맨드라인 도구를 설치합니다. ([npm](http://npmjs.org/) 필요):
```
npm install -g react-tools
```
그다음, `src/helloworld.js` 파일을 일반 JavaScript 파일로 변환합니다:
```
jsx --watch src/ build/
```
수정할 때마다 `build/helloworld.js` 파일이 자동생성됩니다.
```javascript{2}
React.render(
React.createElement('h1', null, 'Hello, world!'),
document.getElementById('example')
);
```
아래의 내용대로 HTML 파일을 업데이트합니다:
```html{6,10}
<!DOCTYPE html>
<html>
<head>
<title>Hello React!</title>
<script src="build/react.js"></script>
<!-- JSXTransformer는 이제 불필요합니다! -->
</head>
<body>
<div id="example"></div>
<script src="build/helloworld.js"></script>
</body>
</html>
```
## CommonJS를 원하시나요?
만약 React를 [browserify](http://browserify.org/), [webpack](http://webpack.github.io/)이나 기타 CommonJS와 호환되는 모듈시스템과 함께 사용하고 싶다면, [`react` npm 패키지](https://www.npmjs.org/package/react)를 사용하세요. 그 외에도 `jsx` 빌드툴은 아주 쉽게 CommonJS 외에도 대부분의 패키징 시스템에 통합될 수 있습니다.
## 다음 단계로
더 알아보려면 [튜토리얼](/react/docs/tutorial-ko-KR.html)과 초심자용 키트의 `examples` 디렉터리에서 다른 예제들을 확인해 보세요.
커뮤니티의 기여로 운영되는 Wiki도 있습니다: [워크플로우, UI 컴포넌트, 라우팅, 데이터 관리 등](https://github.com/facebook/react/wiki/Complementary-Tools)
React의 세계에 오신 것을 환영합니다. 행운을 빌어요!

View File

@@ -0,0 +1,182 @@
---
id: top-level-api-ko-KR
title: 최상위 API
permalink: top-level-api-ko-KR.html
next: component-api-ko-KR.html
redirect_from: "/docs/reference-ko-KR.html"
---
## React
`React`는 React 라이브러리의 진입점입니다. 미리 빌드된 패키지를 사용하는 경우 전역 변수로 접근할 수 있습니다. CommonJS 모듈을 사용하는 경우에는 `require()`로 불러올 수 있습니다.
### React.Component
```javascript
class Component
```
ES6 클래스 구문을 사용해 React 컴포넌트를 정의했을 때 기본 클래스가 되는 부분입니다. 어떻게 ES6 클래스 구문을 사용해 React를 다루는지는 [재사용가능한 컴포넌트](/react/docs/reusable-components-ko-KR.html#es6-classes)를 확인하세요. 기본 클래스에서 실제 제공되는 메소드들에는 어떤것이 있는지 알아보려면 [컴포넌트 API](/react/docs/component-api-ko-KR.html)를 확인하세요.
### React.createClass
```javascript
ReactClass createClass(object specification)
```
주어진 명세에 따라 컴포넌트 클래스를 만듭니다. 컴포넌트는 단 하나의 자식만을 리턴하는 `render` 메소드를 구현합니다. 그 자식은 임의 깊이의 자식 구조를 가질 수 있습니다. 컴포넌트가 일반적인 프로토타입 기반의 클래스와 다른 점은 생성할 때 `new` 연산자를 사용하지 않아도 된다는 것입니다. 컴포넌트는 (`new` 연산자를 통해) 내부 인스턴스를 만들어 주는 편의 래퍼(wrapper)입니다.
명세 객체에 대한 자세한 정보는 [컴포넌트 명세와 생명주기](/react/docs/component-specs-ko-KR.html)를 참고하세요.
### React.createElement
```javascript
ReactElement createElement(
string/ReactClass type,
[object props],
[children ...]
)
```
주어진 타입의 새 `ReactElement`를 만들고 리턴합니다. `type` 인자는 HTML 태그명 문자열 (예: 'div', 'span' 등) 또는 (`React.createClass`로 만든) `ReactClass`입니다.
### React.cloneElement
```
ReactElement cloneElement(
ReactElement element,
[object props],
[children ...]
)
```
`element`를 시작점으로 새로운 `ReactElement`를 클론해 반환합니다. 반환된 엘리먼트에는 원본의 props와 새로운 props가 얕게 병합됩니다. 새 자식은 존재하는 자식을 교체할 것입니다. `React.addons.cloneWithProps`와는 다르게, 원본 엘리먼트의 `key``ref`는 보존될 것입니다. `cloneWithProps`와는 달리 props이 병합되는데는 어떠한 특별한 동작도 없습니다. [v0.13 RC2 블로그 포스트](/react/blog/2015/03/03/react-v0.13-rc2.html)에서 추가적인 내용을 확인하세요.
### React.createFactory
```javascript
factoryFunction createFactory(
string/ReactClass type
)
```
주어진 타입의 ReactElement를 만들어주는 함수를 리턴합니다. `React.createElement`와 마찬가지로 `type` 인자는 HTML 태그명 문자열 (예: 'div', 'span' 등) 또는 `ReactClass`입니다.
### React.render
```javascript
ReactComponent render(
ReactElement element,
DOMElement container,
[function callback]
)
```
주어진 ReactElement를 `container` 인자에 넘어온 DOM 안에 렌더링하고 컴포넌트의 레퍼런스를 리턴합니다.
어떤 ReactElement가 이미 `container`에 렌더링 된 적이 있다면, 그것을 업데이트한 뒤 React 컴포넌트의 최신 상태를 반영하기 위해 꼭 필요한 만큼만 DOM을 변경합니다.
콜백 인자를 넘기면 컴포넌트가 렌더링되거나 업데이트 된 다음 호출됩니다.
> 주의:
>
> `React.render()`는 넘어온 컨테이너 노드의 내용을 교체합니다.
> 추후에 기존 자식들을 덮어쓰지 않고 이미 있는 DOM 노드에 컴포넌트를 삽입하는 것도 지원할 가능성이 있습니다.
### React.unmountComponentAtNode
```javascript
boolean unmountComponentAtNode(DOMElement container)
```
DOM에 마운트된 React 컴포넌트를 제거하고 이벤트 핸들러 및 state를 정리합니다. 컨테이너에 마운트된 컴포넌트가 없는 경우에는 호출해도 아무 동작을 하지 않습니다. 컴포넌트가 마운트 해제된 경우 `true`를, 마운트 해제할 컴포넌트가 없으면 `false`를 리턴합니다.
### React.renderToString
```javascript
string renderToString(ReactElement element)
```
주어진 ReactElement의 최초 HTML을 렌더링합니다. 이 함수는 서버에서만 사용해야 합니다. React가 HTML 문자열을 리턴합니다. HTML을 서버에서 생성하고 마크업을 최초 요청에 내려보내서, 페이지 로딩을 빠르게 하거나 검색 엔진이 크롤링할 수 있도록 하는 SEO 목적으로 이 메소드를 사용할 수 있습니다.
또한 이 메소드로 서버에서 렌더링한 마크업을 포함한 노드에 `React.render()`를 호출하면, React는 마크업을 보존하고 이벤트 핸들러만 붙이므로 최초 로딩을 매우 빠르게 느껴지게 할 수 있습니다.
### React.renderToStaticMarkup
```javascript
string renderToStaticMarkup(ReactElement element)
```
`renderToString`와 비슷하지만 `data-react-id`처럼 React에서 내부적으로 사용하는 추가적인 DOM 어트리뷰트를 만들지 않습니다. 추가적인 어트리뷰트를 제거하면 생성되는 마크업의 용량을 줄일 수 있기 때문에 React를 단순한 정적 페이지 생성기로 사용할 때 유용합니다.
### React.isValidElement
```javascript
boolean isValidElement(* object)
```
주어진 객체가 ReactElement인지 확인합니다.
### React.findDOMNode
```javascript
DOMElement findDOMNode(ReactComponent component)
```
이 컴포넌트가 DOM에 마운트된 경우 해당하는 네이티브 브라우저 DOM 엘리먼트를 리턴합니다. 이 메소드는 폼 필드의 값이나 DOM의 크기/위치 등 DOM에서 정보를 읽을 때 유용합니다. `render``null`이나 `false`를 리턴할 때 `findDOMNode()``null`을 리턴합니다.
### React.DOM
`React.DOM`은 DOM 컴포넌트에 대해 `React.createElement`의 편의 래퍼(wrapper)를 제공합니다. JSX를 사용하지 않는 경우에만 사용하십시오. 예를 들어, `React.DOM.div(null, 'Hello World!')`와 같이 사용할 수 있습니다.
### React.PropTypes
`React.PropTypes`는 컴포넌트에 넘어오는 props가 올바른지 검사할 수 있는 컴포넌트의 `propTypes` 객체에 들어가는 타입을 가집니다. `propTypes`에 대한 자세한 정보는 [재사용 가능한 컴포넌트](/react/docs/reusable-components-ko-KR.html)를 참고하세요.
### React.Children
`React.Children`은 불투명한 자료 구조인 `this.props.children`를 다룰 수 있는 유틸리티를 제공합니다.
#### React.Children.map
```javascript
object React.Children.map(object children, function fn [, object context])
```
`children`의 바로 밑에 있는 모든 자식에 `fn`을 호출합니다. 이 때 `this``context`로 설정됩니다. `children`이 중첩된 객체나 배열일 경우 그 안의 값을 순회합니다. 따라서 `fn`에 컨테이너 객체가 넘어가는 일은 일어나지 않습니다. `children``null`이거나 `undefined`면 빈 객체 대신 `null` 또는 `undefined`를 리턴합니다.
#### React.Children.forEach
```javascript
React.Children.forEach(object children, function fn [, object context])
```
`React.Children.map()`과 비슷하지만 객체를 리턴하지 않습니다.
#### React.Children.count
```javascript
number React.Children.count(object children)
```
`children`에 들어있는 컴포넌트의 총 갯수를 리턴합니다. 이 갯수는 `map`이나 `forEach`에 넘긴 콜백이 호출되는 횟수와 동일합니다.
#### React.Children.only
```javascript
object React.Children.only(object children)
```
`children`에 단 하나의 자식이 있을 때 그 자식을 리턴합니다. 그 밖의 경우에는 예외를 발생시킵니다.

View File

@@ -137,7 +137,7 @@ Verifies the object is a ReactElement.
```javascript
DOMElement findDOMNode(ReactComponent component)
```
If this component has been mounted into the DOM, this returns the corresponding native browser DOM element. This method is useful for reading values out of the DOM, such as form field values and performing DOM measurements. When `render` returns `null` or `false`, `this.getDOMNode()` returns `null`.
If this component has been mounted into the DOM, this returns the corresponding native browser DOM element. This method is useful for reading values out of the DOM, such as form field values and performing DOM measurements. When `render` returns `null` or `false`, `findDOMNode` returns `null`.
### React.DOM

View File

@@ -0,0 +1,134 @@
---
id: component-api-ko-KR
title: 컴포넌트 API
permalink: component-api-ko-KR.html
prev: top-level-api-ko-KR.html
next: component-specs-ko-KR.html
---
## React.Component
React 컴포넌트의 인스턴스는 React가 렌더링 시에 내부적으로 만듭니다. 이때 만들어진 인스턴스는 이후의 렌더링에서 다시 사용되고 컴포넌트의 메소드들에서 `this` 변수로 접근할 수 있습니다. React 외부에서 React 컴포넌트의 핸들을 얻는 방법은 `React.render`의 리턴값을 저장하는 것이 유일합니다. 다른 컴포넌트 안에서 비슷한 결과를 얻으려면 [refs](/react/docs/more-about-refs-ko-KR.html)를 사용해야 합니다.
### setState
```javascript
setState(function|object nextState[, function callback])
```
`nextState`를 현재 state에 합칩니다. 이벤트 핸들러와 서버 요청 콜백에서 UI 업데이트를 발생시키기 위해 이 메소드를 주로 사용합니다.
첫번째 인자는 업데이트를 위한 키를 0개 이상 가진 객체이거나 업데이트를 위한 키들을 포함한 객체를 반환하는 함수(의 state나 props)일 수 있습니다.
객체를 사용하는 간단한 예제입니다...
```javascript
setState({mykey: '새로운 값'});
```
`function(state, props)`처럼 인자를 포함한 함수를 넘겨주는 것도 가능합니다. 어떤 값이든 state와 props의 이전 값을 참고해서 원자적인 업데이트를 큐에 추가(enqueue)하려는 경우 이는 유용합니다. 예를 들어 state의 값을 증가 시키려는 경우 같이 처리 가능합니다:
```javascript
setState(function(previousState, currentProps) {
return {myInteger: previousState.myInteger + 1};
});`
```
두번째 인자는 선택적이며, `setState`가 한번 완료되고 컴포넌트가 다시 렌더 되었을때 실행되는 콜백 함수입니다.
> 주의:
>
> *절대로* `this.state`를 직접 변경하지 마세요. 그 뒤에 `setState()`를 호출하면 그동안 변경했던 것이 교체될 수 있습니다. `this.state`는 변경 불가능한 것으로 생각하시는 것이 좋습니다.
>
> `setState()`를 호출해도 `this.state`가 곧바로 변경되지 않고 대기 중인 state transition이 만들어집니다. 이 메소드를 호출한 직후 `this.state`에 접근하면 바뀌기 전의 값을 리턴할 가능성이 있습니다.
>
> `setState`에 대한 호출이 동기적으로 처리된다는 보장이 없으며, 성능 향상을 위해 배치 처리될 수 있습니다.
>
> `setState()`는 `shouldComponentUpdate()`에 조건부 렌더링 로직이 구현되어 있지 않다면 항상 재렌더링을 발생시킵니다. 변경 가능한 객체를 사용하고 있고 조건부 렌더링 로직을 `shouldComponentUpdate()`에 구현할 수 없는 경우라면 새로운 state가 이전 state와 달라지는 경우에만 `setState()`를 호출하여 불필요한 재렌더링을 피할 수 있습니다.
### replaceState
```javascript
replaceState(object nextState[, function callback])
```
`setState()`와 비슷하지만 기존에 존재하는 state 중 nextState에 없는 키는 모두 삭제됩니다.
> 주의:
>
> 이 메소드는 `React.Component`를 확장한 ES6 `class` 컴포넌트에서는 사용할 수 없습니다. React의 미래 버전에서 이는 완전히 사라지게 될 것입니다.
### forceUpdate
```javascript
forceUpdate([function callback])
```
`render()` 메소드가 `this.props``this.state`가 아닌 다른 곳에서 데이터를 읽어오는 경우 `forceUpdate()`를 호출하여 React가 `render()`를 다시 실행하도록 만들 수 있습니다. `this.state`를 직접 변경하는 경우에도 `forceUpdate()`를 호출해야 합니다.
`forceUpdate()`를 호출하면 `shouldComponentUpdate()`를 생략하고 해당 컴포넌트 `render()` 함수가 호출됩니다. 각 자식 컴포넌트에 대해서는 `shouldComponentUpdate()`를 포함해 보통 라이프 사이클 메서드를 호출합니다. React는 마크업이 변경된 경우에만 DOM을 업데이트합니다.
특별한 경우가 아니면 `forceUpdate()`는 되도록 피하시고 `render()`에서는 `this.props``this.state`에서만 읽어오세요. 그렇게 하는 것이 애플리케이션을 훨씬 단순하고 효율적으로 만들어줍니다.
### getDOMNode
```javascript
DOMElement getDOMNode()
```
이 컴포넌트가 DOM에 마운트된 경우 해당하는 네이티브 브라우저 DOM 엘리먼트를 리턴합니다. 이 메소드는 폼 필드의 값이나 DOM의 크기/위치 등 DOM에서 정보를 읽을 때 유용합니다. `render``null`이나 `false`를 리턴하였다면 `this.getDOMNode()``null`을 리턴합니다.
> 주의:
>
> getDOMNode는 [React.findDOMNode()](/react/docs/top-level-api.html#react.finddomnode)로 교체되었습니다.
>
> 이 메소드는 `React.Component`를 확장한 ES6 `class` 컴포넌트에서는 사용할 수 없습니다. React의 미래 버전에서 이는 완전히 사라지게 될 것입니다.
### isMounted
```javascript
bool isMounted()
```
`isMounted()`는 컴포넌트가 DOM에 렌더링되었으면 true를, 아니면 false를 리턴합니다. 비동기적으로 `setState()``forceUpdate()`를 호출할 때 이 메소드를 사용하여 오류를 방지할 수 있습니다.
> 주의:
>
> 이 메소드는 `React.Component`를 확장한 ES6 `class` 컴포넌트에서는 사용할 수 없습니다. React의 미래 버전에서 이는 완전히 사라지게 될 것입니다.
### setProps
```javascript
setProps(object nextProps[, function callback])
```
외부 JavaScript 애플리케이션과 연동하는 경우 `React.render()`로 렌더링된 React 컴포넌트에 변경을 알리고 싶을 때가 있습니다.
최상위 컴포넌트를 업데이트할 때 `React.render()`를 같은 노드에 다시 호출하는 것이 바람직한 방법이지만, `setProps()`를 호출해서 props를 바꾸고 재렌더링을 발생시킬 수 있습니다. 콜백 함수를 추가로 넘기면 `setProps`가 완료되고 컴포넌트가 다시 렌더링된 다음에 한번 호출됩니다.
> 주의:
>
> 가능하다면 `React.render()`를 다시 호출하는 선언적인 방법이 더 바람직합니다. 그렇게 하는 편이 업데이트에 대해 생각하는 것을 쉽게 만듭니다. (두가지 방식에 눈에 띄는 성능 차이는 없습니다.)
>
> 이 메소드는 최상위 컴포넌트에만 호출 가능합니다. 다시 말해, `React.render()`에 바로 넘긴 컴포넌트에서만 사용할 수 있고 자식에서는 불가능합니다. 자식 컴포넌트에 `setProps()`를 사용하고 싶다면, 그 대신 반응적인 업데이트의 장점을 활용하여 `render()` 안에서 자식 컴포넌트를 만들 때 새로운 prop을 넘기세요.
>
> 이 메소드는 `React.Component`를 확장한 ES6 `class` 컴포넌트에서는 사용할 수 없습니다. React의 미래 버전에서 이는 완전히 사라지게 될 것입니다.
### replaceProps
```javascript
replaceProps(object nextProps[, function callback])
```
`setProps()`와 비슷하지만 두 객체를 합치는 대신 이전에 존재하던 props를 삭제합니다.
> 주의:
>
> 이 메소드는 `React.Component`를 확장한 ES6 `class` 컴포넌트에서는 사용할 수 없습니다. React의 미래 버전에서 이는 완전히 사라지게 될 것입니다.

View File

@@ -0,0 +1,209 @@
---
id: component-specs-ko-KR
title: 컴포넌트 명세와 생명주기
permalink: component-specs-ko-KR.html
prev: component-api-ko-KR.html
next: tags-and-attributes-ko-KR.html
---
## 컴포넌트 명세
`React.createClass()`를 호출하여 컴포넌트 클래스를 생성할 때, `render` 메소드를 포함한 명세 객체를 제공해야 합니다. 또한 필요한 경우 여기에서 설명하는 다른 생명주기 메소드를 명세 객체에 추가로 제공할 수 있습니다.
### render
```javascript
ReactElement render()
```
`render()` 메소드는 필수 항목입니다.
호출되면 `this.props``this.state`를 토대로 하나의 자식 엘리먼트를 리턴합니다. 이 자식 엘리먼트는 네이티브 DOM 컴포넌트의 가상 표현 (`<div />``React.DOM.div()` 등) 또는 직접 정의한 조합(composite) 컴포넌트가 될 수 있습니다.
아무 것도 렌더링되지 않도록 하려면 `null`이나 `false`를 리턴합니다. React는 지금의 차이 비교 알고리즘이 작동할 수 있도록 내부적으로는 `<noscript>` 태그를 렌더링합니다. `null`이나 `false`를 리턴한 경우, `React.findDOMNode(this)``null`을 리턴합니다.
`render()` 함수는 순수 함수여야 합니다. 즉, 컴포넌트의 상태를 변경하지 않고, 여러번 호출해도 같은 결과를 리턴하며, DOM을 읽고 쓰거나 브라우저와 상호작용(예를 들어 `setTimeout`를 사용)하지 않아야 합니다. 브라우저와 상호작용해야 한다면 `componentDidMount()`나 다른 생명주기 메소드에서 수행해야 합니다. `render()` 함수를 순수 함수로 유지하면 서버 렌더링이 훨씬 쓸만해지고 컴포넌트에 대해 생각하기 쉬워집니다.
### getInitialState
```javascript
object getInitialState()
```
컴포넌트가 마운트되기 전에 한번 호출됩니다. 리턴값은 `this.state`의 초기값으로 사용됩니다.
### getDefaultProps
```javascript
object getDefaultProps()
```
클래스가 생성될 때 한번 호출되고 캐시됩니다. 부모 컴포넌트에서 prop이 넘어오지 않은 경우 (`in` 연산자로 확인) 매핑의 값이 `this.props`에 설정됩니다.
이 메소드는 인스턴스가 만들어지기 전에 호출되므로 `this.props`에 의존할 수 없습니다. 그리고 `getDefaultProps()`의 리턴값에 포함된 복잡한 객체는 복사되지 않고 인스턴스 간에 공유됩니다.
### propTypes
```javascript
object propTypes
```
`propTypes` 객체는 컴포넌트에 넘어오는 props가 올바른지 검사할 수 있게 해줍니다. `propTypes`에 대한 자세한 정보는 [재사용 가능한 컴포넌트](/react/docs/reusable-components-ko-KR.html)를 참고하세요.
### mixins
```javascript
array mixins
```
`mixins` 배열은 여러 컴포넌트 사이에 동작을 공유하는 믹스인을 사용할 수 있게 해줍니다. 믹스인에 대한 자세한 정보는 [재사용 가능한 컴포넌트](/react/docs/reusable-components-ko-KR.html)를 참고하세요.
### statics
```javascript
object statics
```
`statics` 객체는 컴포넌트 클래스의 스태틱 메소드를 정의할 수 있게 해줍니다. 에를 들어:
```javascript
var MyComponent = React.createClass({
statics: {
customMethod: function(foo) {
return foo === 'bar';
}
},
render: function() {
}
});
MyComponent.customMethod('bar'); // true
```
이 블럭 안에서 정의된 메소드는 인스턴스를 하나도 만들지 않은 시점에도 호출할 수 있고, 컴포넌트의 props나 state에 접근할 수 없습니다. 스태틱 메소드에서 props의 값을 확인하려면 호출자가 스태틱 메소드에 props를 인자로 넘기도록 해야합니다.
### displayName
```javascript
string displayName
```
`displayName` 문자열은 디버그 메시지에 사용됩니다. JSX는 이 값을 자동으로 설정합니다. [JSX 깊이 알기](/react/docs/jsx-in-depth-ko-KR.html#the-transform)를 참고하세요.
<a name="lifecycle-methods"></a>
## 생명주기 메소드
컴포넌트의 생명주기에서 특정 시점마다 실행되는 메소드들입니다.
### 마운트 시: componentWillMount
```javascript
componentWillMount()
```
최초 렌더링이 일어나기 직전에 클라이언트 및 서버에서 한번 호출됩니다. 이 메소드 안에서 `setState`를 호출하면, `render()`에서 업데이트된 state를 확인할 수 있고 state가 변함에도 불구하고 `render()`가 한번만 실행됩니다.
### 마운트 시: componentDidMount
```javascript
componentDidMount()
```
최초 렌더링이 일어난 다음 클라이언트에서만 한번 호출됩니다. (서버에서는 호출되지 않습니다.) 이 시점에 컴포넌트는 `React.findDOMNode(this)`로 접근 가능한 DOM 표현을 가집니다.
다른 JavaScript 프레임워크를 연동하거나, `setTimeout`/`setInterval`로 타이머를 설정하고 AJAX 요청을 보내는 등의 작업을 이 메소드에서 합니다.
### 업데이트 시: componentWillReceiveProps
```javascript
componentWillReceiveProps(object nextProps)
```
컴포넌트가 새로운 props를 받을 때 호출됩니다. 이 메소드는 최초 렌더링 시에는 호출되지 않습니다.
`render()`가 호출되기 전에 prop의 변화를 감지하여 `this.setState()`를 호출해서 state를 업데이트할 수 있습니다. 이전 props는 `this.props`로 접근할 수 있습니다. 이 함수 안에서 `this.setState()`를 호출해도 추가 렌더링이 발생하지 않습니다.
```javascript
componentWillReceiveProps: function(nextProps) {
this.setState({
likesIncreasing: nextProps.likeCount > this.props.likeCount
});
}
```
> 주의:
>
> `componentWillReceiveState`에 해당하는 메소드는 없습니다. prop이 변할 때 state가 바뀔 수는 있지만, 그 역은 불가능합니다. state의 변화에 따라 작업을 실행해야 하면 `componentWillUpdate`를 사용하세요.
<a name="updating-shouldcomponentupdate"></a>
### 업데이트 시: shouldComponentUpdate
```javascript
boolean shouldComponentUpdate(object nextProps, object nextState)
```
새로운 props 또는 state를 받아 렌더링을 하기 전에 호출됩니다. 최초 렌더링 시나 `forceUpdate`를 사용하는 경우에는 호출되지 않습니다.
새로운 props와 state가 컴포넌트 업데이트를 필요로 하지 않는 것이 확실하다면
`false`를 리턴하세요.
```javascript
shouldComponentUpdate: function(nextProps, nextState) {
return nextProps.id !== this.props.id;
}
```
`shouldComponentUpdate`가 false를 리턴하면, 다음에 state가 바뀌기 전까지 `render()`가 완전히 호출되지 않고 넘어갑니다. (그리고 `componentWillUpdate``componentDidUpdate` 또한 호출되지 않습니다.)
기본적으로 `shouldComponentUpdate`는 항상 true를 리턴합니다. `state`가 제자리에서(in place) 바뀐 경우에 발생하는 파악하기 힘든 버그를 막기 위함입니다. 하지만 `state`가 항상 변경 불가능하도록 주의하고 `render()`에서 `props``state`를 읽기만 하면 이전 props 및 state와 바뀌는 값을 비교하는 `shouldComponentUpdate`를 직접 구현할 수 있습니다.
성능에 병목이 있다면, 특히 컴포넌트가 매우 많은 경우 `shouldComponentUpdate`를 사용하여 앱을 빠르게 만들 수 있습니다.
### 업데이트 시: componentWillUpdate
```javascript
componentWillUpdate(object nextProps, object nextState)
```
새로운 props나 state를 받았을 때 렌더링 직전에 호출됩니다. 최초 렌더링 시에는 호출되지 않습니다.
업데이트가 일어나기 전에 준비하기 위해 사용할 수 있습니다.
> 주의:
>
> 이 메소드에서는 `this.setState()`를 호출할 수 없습니다. prop 변화에 반응하여 state를 업데이트해야 할 경우, `componentWillReceiveProps`를 대신 사용하세요.
### 업데이트 시: componentDidUpdate
```javascript
componentDidUpdate(object prevProps, object prevState)
```
컴포넌트의 업데이트가 DOM에 반영된 직후에 호출됩니다. 최초 렌더링 시에는 호출되지 않습니다.
컴포넌트가 업데이트된 뒤 DOM을 조작해야 하는 경우 사용할 수 있습니다.
### 마운트 해제 시: componentWillUnmount
```javascript
componentWillUnmount()
```
컴포넌트가 DOM에서 마운트 해제 되기 직전에 호출됩니다.
이 메소드에서 타이머를 무효화하거나 `componentDidMount`에서 만들어진 DOM 엘리먼트를 정리하는 등 필요한 정리 작업을 수행할 수 있습니다.

View File

@@ -14,12 +14,12 @@ When creating a component class by invoking `React.createClass()`, you should pr
### render
```javascript
ReactComponent render()
ReactElement 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 virtual representation of a native DOM component (such as `<div />` or `React.DOM.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 element. This child element 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.
You can also return `null` or `false` to indicate that you don't want anything rendered. Behind the scenes, React renders a `<noscript>` tag to work with our current diffing algorithm. When returning `null` or `false`, `React.findDOMNode(this)` will return `null`.

View File

@@ -0,0 +1,84 @@
---
id: tags-and-attributes-ko-KR
title: 태그와 어트리뷰트
permalink: tags-and-attributes-ko-KR.html
prev: component-specs-ko-KR.html
next: events-ko-KR.html
---
## 지원되는 태그
React는 모든 공통 엘리먼트를 지원하려 합니다. 필요한 엘리먼트가 목록에 없다면, 이슈로 등록해 주세요.
### HTML 엘리먼트
다음의 HTML 엘리먼트가 지원됩니다.
```
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
dialog 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 picture 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 엘리먼트
다음의 SVG 엘리먼트가 지원됩니다.
```
circle defs ellipse g line linearGradient mask path pattern polygon polyline
radialGradient rect stop svg text tspan
```
아마 Canvas, SVG, VML(IE8 전용)에 렌더할 때 쓰는 React의 드로잉 라이브러리인 [react-art](https://github.com/facebook/react-art)도 흥미 있으실 수 있습니다.
## 지원되는 어트리뷰트
React는 모든 `data-*`, `aria-*` 어트리뷰트와 밑에 있는 모든 어트리뷰트를 지원합니다.
> 주의:
>
> 모든 어트리뷰트는 카멜케이스이고, `class` `for` 어트리뷰트는 각각 DOM API의 사양에 맞춰서 `className` `htmlFor` 가 됩니다.
이벤트의 목록을 보시려면 [지원되는 이벤트](/react/docs/events-ko-KR.html)를 확인하세요.
### HTML 어트리뷰트
이런 표준 어트리뷰트가 지원됩니다.
```
accept acceptCharset accessKey action allowFullScreen allowTransparency alt
async autoComplete autoFocus autoPlay cellPadding cellSpacing charSet checked classID
className cols colSpan content contentEditable contextMenu controls coords
crossOrigin data dateTime defer dir disabled download draggable encType form
formAction formEncType formMethod formNoValidate formTarget frameBorder height
hidden href hrefLang htmlFor httpEquiv icon id label lang list loop manifest
marginHeight marginWidth max maxLength media mediaGroup method min multiple
muted name noValidate open pattern placeholder poster preload radioGroup
readOnly rel required role rows rowSpan sandbox scope scoped scrolling seamless
selected shape size sizes span spellCheck src srcDoc srcSet start step style
tabIndex target title type useMap value width wmode
```
덧붙여, 이런 비표준 어트리뷰트도 지원됩니다.
- 모바일 사파리를 위한 `autoCapitalize autoCorrect`.
- [오픈 그래프](http://ogp.me/) 메타 태그를 위한 `property`.
- [HTML5 마이크로데이터](http://schema.org/docs/gs.html)를 위한 `itemProp itemScope itemType itemRef itemId`.
컴포넌트에 직접 HTML 문자열을 넣을 때 사용하는, React 전용 어트리뷰트 `dangerouslySetInnerHTML`([자세한 정보는 여기](/react/docs/special-non-dom-attributes-ko-KR.html))도 있습니다.
### SVG 어트리뷰트
```
cx cy d dx dy fill fillOpacity fontFamily fontSize fx fy gradientTransform
gradientUnits markerEnd markerMid markerStart offset opacity
patternContentUnits patternUnits points preserveAspectRatio r rx ry
spreadMethod stopColor stopOpacity stroke strokeDasharray strokeLinecap
strokeOpacity strokeWidth textAnchor transform version viewBox x1 x2 x y1 y2 y
```

View File

@@ -60,7 +60,7 @@ formAction formEncType formMethod formNoValidate formTarget frameBorder height
hidden href hrefLang htmlFor httpEquiv icon id label lang list loop manifest
marginHeight marginWidth max maxLength media mediaGroup method min multiple
muted name noValidate open pattern placeholder poster preload radioGroup
readOnly rel required role rows rowSpan sandbox scope scrolling seamless
readOnly rel required role rows rowSpan sandbox scope scoped scrolling seamless
selected shape size sizes span spellCheck src srcDoc srcSet start step style
tabIndex target title type useMap value width wmode
```

View File

@@ -0,0 +1,194 @@
---
id: events-ko-KR
title: 이벤트 시스템
permalink: events-ko-KR.html
prev: tags-and-attributes-ko-KR.html
next: dom-differences-ko-KR.html
---
## 통합적인(Synthetic) 이벤트
이벤트 핸들러는 브라우저의 네이티브 이벤트의 크로스 브라우저 래퍼(wrapper)인`SyntheticEvent`의 인스턴스에 전달됩니다. 모든 브라우저에서 동작한다는 점을 제외하면, `SyntheticEvent``stopPropagation()``preventDefault()`를 포함해, 브라우저의 네이티브 이벤트와 같은 인터페이스를 가지고 있습니다.
어떤 이유로 기본 브라우저 이벤트가 필요하다면, 그냥 `nativeEvent`를 사용해 할 수 있습니다. 모든 `SyntheticEvent` 객체는 이런 어트리뷰트를 가집니다.
```javascript
boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
number eventPhase
boolean isTrusted
DOMEvent nativeEvent
void preventDefault()
void stopPropagation()
DOMEventTarget target
number timeStamp
string type
```
> 주의:
>
> v0.12 시점에서, 이벤트 핸들러에서 `false` 를 리턴하는 것은 더 이상 이벤트의 전달(propagation)을 멈추지 않습니다. 대신, `e.stopPropagation()`나 `e.preventDefault()`로 적절히 수동으로 트리거해야 합니다.
## 지원되는 이벤트
React는 다른 브라우저에서 일관된 특성을 가지도록 이벤트를 일반화합니다.
밑에 있는 이벤트 핸들러들은 일으키는(bubbling) 단계에서 이벤트를 트리거합니다. 이벤트 핸들러를 캡처 단계로 등록하려면, 이벤트 이름에 `Capture`를 붙이면 됩니다. 예를 들어, 캡처 단계의 클릭 이벤트를 다루려면 `onClick`를 사용하는 대신에 `onClickCapture`를 사용해야 합니다.
### 클립보드 이벤트
이벤트 이름:
```
onCopy onCut onPaste
```
프로퍼티:
```javascript
DOMDataTransfer clipboardData
```
### 키보드 이벤트
이벤트 이름:
```
onKeyDown onKeyPress onKeyUp
```
프로퍼티:
```javascript
boolean altKey
Number charCode
boolean ctrlKey
function getModifierState(key)
String key
Number keyCode
String locale
Number location
boolean metaKey
boolean repeat
boolean shiftKey
Number which
```
### 포커스 이벤트
이벤트 이름:
```
onFocus onBlur
```
프로퍼티:
```javascript
DOMEventTarget relatedTarget
```
<a name="form-events"></a>
### 폼 이벤트
이벤트 이름:
```
onChange onInput onSubmit
```
onChange 이벤트에 대한 더 자세한 정보는 [](/react/docs/forms-ko-KR.html)에서 확인하세요.
### 마우스 이벤트
이벤트 이름:
```
onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave
onMouseMove onMouseOut onMouseOver onMouseUp
```
`onMouseEnter``onMouseLeave` 이벤트는 평범하게 일어나는(bubbling) 대신 입력된 컴포넌트에 남겨지도록 컴포넌트에서 전달되고 캡쳐 단계가 없습니다.
프로퍼티:
```javascript
boolean altKey
Number button
Number buttons
Number clientX
Number clientY
boolean ctrlKey
function getModifierState(key)
boolean metaKey
Number pageX
Number pageY
DOMEventTarget relatedTarget
Number screenX
Number screenY
boolean shiftKey
```
### 터치 이벤트
이벤트 이름:
```
onTouchCancel onTouchEnd onTouchMove onTouchStart
```
프로퍼티:
```javascript
boolean altKey
DOMTouchList changedTouches
boolean ctrlKey
function getModifierState(key)
boolean metaKey
boolean shiftKey
DOMTouchList targetTouches
DOMTouchList touches
```
### UI 이벤트
이벤트 이름:
```
onScroll
```
프로퍼티:
```javascript
Number detail
DOMAbstractView view
```
### 휠 이벤트
이벤트 이름:
```
onWheel
```
프로퍼티:
```javascript
Number deltaMode
Number deltaX
Number deltaY
Number deltaZ
```

View File

@@ -0,0 +1,17 @@
---
id: dom-differences-ko-KR
title: DOM과의 차이점
permalink: dom-differences-ko-KR.html
prev: events-ko-KR.html
next: special-non-dom-attributes-ko-KR.html
---
React는 성능과 크로스 브라우저 호환성을 이유로 브라우저에 독립적인 이벤트와 DOM 시스템으로 구현되었습니다. 브라우저 DOM 구현의 일관성없는 부분들을 정리할 기회를 가졌습니다.
* 모든 DOM 프로퍼티와 어트리뷰트는 (이벤트 핸들러를 포함해) 표준 JavaScript 스타일과 일치하도록 카멜케이스를 사용해야 합니다. **하지만**, `data-*``aria-*` 어트리뷰트는 [사양을 준수해](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#data-*) 소문자만 사용해야 합니다.
* `style` 어트리뷰트는 CSS 문자열 대신에 카멜케이스로 된 프로퍼티를 가지는 JavaScript 객체를 받습니다. 이는 DOM `style` JavaScript 프로퍼티와 일치하면서도 좀 더 효율적이며, XSS 보안 취약점을 예방할 수 있습니다.
* 모든 이벤트 객체는 W3C 사양을 준수하고, 모든 이벤트(submit을 포함해)는 W3C 사양에 따라 일으킵(bubble)니다. 좀 더 자세한 정보는 [이벤트 시스템](/react/docs/events-ko-KR.html)을 보세요.
* `onChange` 이벤트는 기대대로 동작합니다. 이 이벤트는 일관성없이 blur시점에서 발생하지 않고 폼 필드가 변경될 때만 발생합니다.[^1] 우리는 의도적으로 기존 브라우저 동작을 차단했습니다. `onChange`는 이름과 실제 동작이 다르고, React는 실시간으로 사용자 입력에 반응할 때 이 이벤트에 의존하기 때문입니다. 더 자세한 정보는 [](/react/docs/forms-ko-KR.html)을 보세요.
* `value``checked` 폼 input 어트리뷰트, `textarea`. [자세히 보기](/react/docs/forms-ko-KR.html).
[^1]: **역주**: 일관성 없다는 표현에 대해 부연 설명하자면, 네이티브의 onChange는 변경뿐만 아니라 blur에서도 반응합니다.

View File

@@ -0,0 +1,13 @@
---
id: special-non-dom-attributes-ko-KR
title: DOM이 아닌 특별한 어트리뷰트
permalink: special-non-dom-attributes-ko-KR.html
prev: dom-differences-ko-KR.html
next: reconciliation-ko-KR.html
---
[DOM 차이점](/react/docs/dom-differences-ko-KR.html)처럼, React는 DOM에는 존재하지 않는 몇몇 어트리뷰트도 제공합니다.
- `key`: 선택적인 고유 식별자. 컴포넌트가 `render` 과정에서 섞일 때, diff 알고리즘에 의해 파괴되고, 다시 생성될 수 있습니다. 컴포넌트에 영속적인(persists) 키를 할당하면 컴포넌트가 확실히 유지되게 할 수 있습니다. 더 자세한 것은 [여기](/react/docs/multiple-components-ko-KR.html#dynamic-children)에서 보세요.
- `ref`: [여기](/react/docs/more-about-refs-ko-KR.html)를 보세요.
- `dangerouslySetInnerHTML`: 생(raw) HTML을 넣을 수 있게 합니다. 주로 DOM 문자열 관리 라이브러리와의 협력하기 위해 사용합니다. 더 자세한 것은 [여기](/react/tips/dangerously-set-inner-html.html)를 보세요.

View File

@@ -0,0 +1,132 @@
---
id: reconciliation-ko-KR
title: 비교조정(Reconciliation)
permalink: reconciliation-ko-KR.html
prev: special-non-dom-attributes-ko-KR.html
next: glossary-ko-KR.html
---
React의 주요 설계 철학은 업데이트할 때마다 전체 앱을 다시 렌더하는 것처럼 보이게 API를 만드는 것입니다. 이렇게 하면 애플리케이션 작성이 훨씬 쉬워지지만 한편으로는 어려운 도전 과제이기도 합니다. 이 글에서는 강력한 휴리스틱으로 어떻게 O(n<sup>3</sup>) 복잡도의 문제를 O(n)짜리로 바꿀 수 있었는지 설명합니다.
## 동기
최소한의 연산으로 어떤 트리를 다른 트리로 바꾸는 것은 복잡하고 많이 연구된 문제입니다. n을 트리에 있는 노드 수라고 할 때 [최신 알고리즘](http://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf)은 O(n<sup>3</sup>) 복잡도를 가집니다.
다시 말해 1000개의 노드를 표시하려면 10억 번 수준의 비교를 해야 한다는 뜻입니다. 이는 우리가 필요한 용도로는 너무 비쌉니다. 이 수치를 좀 더 알기 쉽게 설명하면, 요즘 CPU는 1초에 대략 30억 번의 연산을 하므로 가장 빠른 구현으로도 1초 안에 이러한 비교는 계산해낼 수 없다는 것입니다.
최적의 알고리즘을 사용할 수 없기 때문에, 완전하진 않지만 다음의 두 가지 가정에 기반한 휴리스틱을 사용한 O(n) 알고리즘으로 구현했습니다.
1. 같은 클래스의 두 컴포넌트는 비슷한 트리를 생성하고, 서로 다른 클래스를 가진 두 컴포넌트는 서로 다른 트리를 생성할 것이다.
2. 각 렌더 과정들 사이에 유지되는 엘리먼트에 고유한 키를 제공할 수 있다.
실제로 이러한 가정은 거의 모든 실용적인 상황에서 굉장히 빠릅니다.
## 일대일 비교
트리 비교를 하기 위해서는 먼저 두 노드를 비교할 수 있어야 합니다. 세 가지 경우를 다룹니다.
### 서로 다른 노드 타입
두 노드의 타입이 서로 다르다면, React는 이를 두 개의 서로 다른 서브트리로 간주해 처음 것을 버리고 두번째 것을 만들어 삽입합니다.
```xml
renderA: <div />
renderB: <span />
=> [removeNode <div />], [insertNode <span />]
```
동일한 로직이 커스텀 컴포넌트에 대해서도 적용됩니다. 타입이 다르다면 React는 그 컴포넌트들이 무엇을 렌더하는지 조차도 비교하지 않습니다. 그저 처음 것을 DOM에서 제거하고 두번째 것을 삽입합니다.
```xml
renderA: <Header />
renderB: <Content />
=> [removeNode <Header />], [insertNode <Content />]
```
이러한 고수준의 사실을 알 수 있다는 것이 React의 비교 알고리즘이 빠르면서 정확할 수 있는 비결입니다. 트리의 커다란 부분을 일찌감치 탐색 대상에서 제외하고 비슷할 가능성이 높은 부분에 집중할 수 있는 좋은 휴리스틱을 제공합니다.
`<Header>` 엘리먼트가 생성하는 DOM이 `<Content>`가 생성하는 것과 비슷하게 생길 확률은 매우 낮습니다. 이 두 구조를 비교하는데 시간을 낭비하지 않고 React는 그냥 트리를 처음부터 새로 만듭니다.
한편 두 번의 연속적인 렌더에서 같은 위치에 `<Header>` 엘리먼트가 있다면 비슷한 구조일 것이므로 탐색할만 합니다.
### DOM 노드
두 DOM 노드를 비교할 때는 어트리뷰트를 보고 무엇이 바뀌었는지 선형 시간 안에 결정할 수 있습니다.
```xml
renderA: <div id="before" />
renderB: <div id="after" />
=> [replaceAttribute id "after"]
```
스타일을 불명확한 문자열로 다루지 않고 키-값 객체를 사용합니다. 이는 변경된 프로퍼티만 업데이트 하도록 해줍니다.
```xml
renderA: <div style={{'{{'}}color: 'red'}} />
renderB: <div style={{'{{'}}fontWeight: 'bold'}} />
=> [removeStyle color], [addStyle font-weight 'bold']
```
어트리뷰트가 업데이트된 다음에는, 모든 자식도 재귀적으로 업데이트합니다.
### 커스텀 컴포넌트
우리는 두 커스텀 컴포넌트를 같은 것으로 취급하기로 했습니다. 컴포넌트는 상태를 가지기 때문에 새 컴포넌트를 그냥 사용할 수는 없습니다. React는 새 컴포넌트의 모든 어트리뷰트를 취해 이전 컴포넌트의 `component[Will/Did]ReceiveProps()`를 호출해 줍니다.
이제 이전 컴포넌트가 작동합니다. 거기 있는 `render()` 메소드가 호출되고 비교 알고리즘이 다시 새로운 결과와 이전 결과를 비교합니다.
## 목록끼리 비교
### 문제가 되는 경우
React는 매우 단순한 방식으로 자식 비교조정(children reconciliation)을 합니다. 자식 목록을 동시에 서로 비교하다가 차이를 발견하면 변경 사항을 적용합니다.
예를 들어 맨 끝에 엘리먼트를 추가한 경우에는:
```xml
renderA: <div><span>first</span></div>
renderB: <div><span>first</span><span>second</span></div>
=> [insertNode <span>second</span>]
```
맨 앞에 엘리먼트를 삽입하는 경우가 문제입니다. React는 두 노드가 모두 span인지 확인하고 변경 모드로 작동합니다.
```xml
renderA: <div><span>first</span></div>
renderB: <div><span>second</span><span>first</span></div>
=> [replaceAttribute textContent 'second'], [insertNode <span>first</span>]
```
원소의 목록을 변환하기 위한 최소 연산 집합을 찾는 알고리즘이 여럿 있습니다. [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance)를 사용하면 O(n<sup>2</sup>) 복잡도로 원소 한 개의 삽입, 삭제, 교체를 위해 필요한 최솟값을 찾을 수 있습니다. Levenshtein 알고리즘을 사용해도 노드가 다른 위치로 이동한 경우는 알아낼 수 없고, 그것을 알아내는 알고리즘은 더욱 높은 복잡도를 가집니다.
### 키(keys)
해결할 수 없어보이는 이 문제를 풀기 위해 선택적인 어트리뷰트를 도입했습니다. 각 자식에 키(key)를 할당해 이를 비교하는 데에 사용합니다. 키를 명시하면 React가 해시 테이블을 사용하여 삽입, 삭제, 교체 및 이동을 O(n) 복잡도로 찾아낼 수 있습니다.
```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>]
```
실제 상황에서 키를 찾는 것은 별로 어렵지 않습니다. 대부분의 경우, 표시하려는 엘리먼트는 이미 고유한 식별자를 가지고 있습니다. 그렇지 않은 경우에도 모델에 새로운 ID 프로퍼티를 추가하거나 내용의 일부분을 해시하여 키를 생성할 수 있습니다. 키는 형제 노드 사이에서만 고유하면 됩니다. 전역적으로 고유할 필요는 없습니다.
## 트레이드오프
비교조정 알고리즘이 구현 세부사항이라는 것을 기억하는 것은 중요합니다. React가 전체 앱을 모든 동작마다 새로 렌더해도 결과는 같을 것입니다. 일반적인 사용 패턴을 빠르게 만들 수 있도록 저희는 계속 휴리스틱을 다듬고 있습니다.
현재 구현에서 서브트리가 형제 노드 사이에서 이동하는 경우는 표현할 수 있지만, 그 외의 곳으로 이동했는지는 알 수 없습니다. 알고리즘에 따라 전체 서브트리가 다시 렌더됩니다.
두 가지 휴리스틱에 의존하기 때문에 그에 대한 가정이 만족되지 않으면 성능이 좋지 않을 것입니다.
1. 서로 다른 컴포넌트 클래스의 서브트리는 비교하려고 시도하지 않습니다. 만약 매우 비슷한 출력 결과의 두 컴포넌트를 왔다갔다 하는 경우 같은 클래스로 만들 수 있습니다. 실제 상황에서는 큰 문제가 없습니다.
2. 안정적인 키를 붙이지 않을 경우 (예를 들어 Math.random()을 사용한다거나) 모든 서브트리가 매번 다시 렌더될 것입니다. 사용자에게 키를 선택하도록 하는 대신 실수할 수 있는 여지가 있습니다.

View File

@@ -0,0 +1,193 @@
---
id: glossary-ko-KR
title: React (가상) DOM 용어
permalink: glossary-ko-KR.html
prev: reconciliation-ko-KR.html
---
다음은 React에서 사용되는 용어들로, 이 다섯 가지의 타입을 구별하는 것은 중요합니다.
- [ReactElement / ReactElement 팩토리](#react-elements)
- [ReactNode](#react-nodes)
- [ReactComponent / ReactComponent 클래스](#react-components)
## React 엘리먼트
`ReactElement`는 React의 주요 타입입니다. `type`, `props`, `key`, `ref`의 네 가지 프로퍼티를 가집니다. 메소드는 가지지 않으며 프로토타입에는 아무 것도 들어있지 않습니다.
이러한 객체는 `React.createElement`를 통해 만들 수 있습니다.
```javascript
var root = React.createElement('div');
```
DOM에 새로운 트리를 렌더링하기 위해서는 `ReactElement`를 만들고 일반적인 DOM `Element` (`HTMLElement` 또는 `SVGElement`)와 함께 `React.render`에 넘깁니다. `ReactElement`를 DOM `Element`와 혼동해서는 안됩니다. `ReactElement`는 가볍고, 상태를 갖지 않으며, 변경 불가능한, DOM `Element`의 가상 표현입니다. 즉 가상 DOM입니다.
```javascript
React.render(root, document.getElementById('example'));
```
DOM 엘리먼트에 프로퍼티를 추가하려면 두번째 인자로 프로퍼티 객체를, 세번째 인자로 자식을 넘깁니다.
```javascript
var child = React.createElement('li', null, 'Text Content');
var root = React.createElement('ul', { className: 'my-list' }, child);
React.render(root, document.getElementById('example'));
```
React JSX를 사용하면 `ReactElement`가 알아서 만들어집니다. 따라서 다음 코드는 앞의 코드와 같습니다:
```javascript
var root = <ul className="my-list">
<li>Text Content</li>
</ul>;
React.render(root, document.getElementById('example'));
```
__팩토리__
`ReactElement` 팩토리는 그저 특정한 `type` 프로퍼티를 가지는 `ReactElement`를 만들어주는 함수입니다. React에는 팩토리를 만드는 헬퍼가 내장되어 있습니다. 그 함수는 사실상 다음과 같습니다:
```javascript
function createFactory(type) {
return React.createElement.bind(null, type);
}
```
이를 이용하면 편리한 단축 함수를 만들 수 있어 항상 `React.createElement('div')`를 입력하지 않아도 됩니다.
```javascript
var div = React.createFactory('div');
var root = div({ className: 'my-div' });
React.render(root, document.getElementById('example'));
```
React에는 이미 보통의 HTML 태그를 위한 팩토리가 내장되어 있습니다:
```javascript
var root = React.DOM.ul({ className: 'my-list' },
React.DOM.li(null, 'Text Content')
);
```
JSX를 사용하면 팩토리가 필요하지 않습니다. 이미 JSX가 `ReactElement`를 만드는 편리한 단축 문법을 제공합니다.
## React 노드
`ReactNode`는 다음 중 하나가 될 수 있습니다:
- `ReactElement`
- `string` (`ReactText`로 부르기도 함)
- `number` (`ReactText`로 부르기도 함)
- `ReactNode`의 배열 (`ReactFragment`로 부르기도 함)
이들은 자식을 표현하기 위해 다른 `ReactElement`의 프로퍼티에 사용됩니다. 사실상 이들이 `ReactElement`의 트리를 형성합니다.
## React 컴포넌트
`ReactElement`만 가지고도 React를 사용할 수는 있지만, React의 장점을 제대로 활용하려면 `ReactComponent`를 사용하여 상태를 가진 캡슐화된 객체를 만들기를 원할 것입니다.
`ReactComponent` 클래스는 그냥 JavaScript 클래스 (또는 "생성자 함수")입니다.
```javascript
var MyComponent = React.createClass({
render: function() {
...
}
});
```
이 생성자가 호출될 때 최소한 `render` 메소드를 가진 객체를 리턴해야 합니다. 이 리턴된 객체를 `ReactComponent`라고 부릅니다.
```javascript
var component = new MyComponent(props); // 절대 하지 마세요.
```
테스트 목적이 아니라면 __절대__ 이 생성자를 직접 호출하지 마십시오. React가 알아서 호출해줍니다.
대신 `ReactComponent` 클래스를 `createElement`에 넘겨 `ReactElement`를 받을 수 있습니다.
```javascript
var element = React.createElement(MyComponent);
```
또는 JSX를 사용하면:
```javascript
var element = <MyComponent />;
```
이것이 `React.render`에 넘겨지면 React가 알아서 생성자를 호출하여 `ReactComponent`를 만들고 리턴합니다.
```javascript
var component = React.render(element, document.getElementById('example'));
```
같은 타입의 `ReactElement`와 같은 컨테이너 DOM `Element`를 가지고 `React.render`를 계속 호출하면 항상 같은 인스턴스를 리턴합니다. 이 인스턴스는 상태를 가집니다.
```javascript
var componentA = React.render(<MyComponent />, document.getElementById('example'));
var componentB = React.render(<MyComponent />, document.getElementById('example'));
componentA === componentB; // true
```
그렇기 때문에 직접 인스턴스를 만들어서는 안됩니다. `ReactComponent`가 생성되기 전에 `ReactElement`가 대신 가상의 `ReactComponent` 역할을 합니다. 이전 `ReactElement`와 새 `ReactElement`를 비교하여 새로운 `ReactComponent`를 만들지, 아니면 기존 것을 재사용할지 결정합니다.
`ReactComponent``render` 메소드는 또다른 `ReactElement`를 리턴해야 합니다. 이렇게 해서 컴포넌트들이 조합됩니다. 결과적으로 렌더링 과정은 다음과 같습니다. `string` 타입의 태그를 가진 `ReactElement`를 통해 DOM `Element` 인스턴스가 생성되며 문서에 삽입됩니다.
## 형식 타입 정의
__진입점__
```
React.render = (ReactElement, HTMLElement | SVGElement) => ReactComponent;
```
__노드와 엘리먼트__
```
type ReactNode = ReactElement | ReactFragment | ReactText;
type ReactElement = ReactComponentElement | ReactDOMElement;
type ReactDOMElement = {
type : string,
props : {
children : ReactNodeList,
className : string,
etc.
},
key : string | boolean | number | null,
ref : string | null
};
type ReactComponentElement<TProps> = {
type : ReactClass<TProps>,
props : TProps,
key : string | boolean | number | null,
ref : string | null
};
type ReactFragment = Array<ReactNode | ReactEmpty>;
type ReactNodeList = ReactNode | ReactEmpty;
type ReactText = string | number;
type ReactEmpty = null | undefined | boolean;
```
__클래스와 컴포넌트__
```
type ReactClass<TProps> = (TProps) => ReactComponent<TProps>;
type ReactComponent<TProps> = {
props : TProps,
render : () => ReactElement
};
```

View File

@@ -24,7 +24,7 @@ var root = React.createElement('div');
To render a new tree into the DOM, you create `ReactElement`s and pass them to `React.render` along with a regular DOM `Element` (`HTMLElement` or `SVGElement`). `ReactElement`s are not to be confused with DOM `Element`s. A `ReactElement` is a light, stateless, immutable, virtual representation of a DOM `Element`. It is a virtual DOM.
```javascript
React.render(root, document.body);
React.render(root, document.getElementById('example'));
```
To add properties to a DOM element, pass a properties object as the second argument and children to the third argument.
@@ -32,7 +32,7 @@ To add properties to a DOM element, pass a properties object as the second argum
```javascript
var child = React.createElement('li', null, 'Text Content');
var root = React.createElement('ul', { className: 'my-list' }, child);
React.render(root, document.body);
React.render(root, document.getElementById('example'));
```
If you use React JSX, then these `ReactElement`s are created for you. So this is equivalent:
@@ -41,7 +41,7 @@ If you use React JSX, then these `ReactElement`s are created for you. So this is
var root = <ul className="my-list">
<li>Text Content</li>
</ul>;
React.render(root, document.body);
React.render(root, document.getElementById('example'));
```
__Factories__
@@ -49,7 +49,7 @@ __Factories__
A `ReactElement`-factory is simply a function that generates a `ReactElement` with a particular `type` property. React has a built-in helper for you to create factories. It's effectively just:
```javascript
function createFactory(type){
function createFactory(type) {
return React.createElement.bind(null, type);
}
```
@@ -59,7 +59,7 @@ It allows you to create a convenient short-hand instead of typing out `React.cre
```javascript
var div = React.createFactory('div');
var root = div({ className: 'my-div' });
React.render(root, document.body);
React.render(root, document.getElementById('example'));
```
React already has built-in factories for common HTML tags:
@@ -122,14 +122,14 @@ var element = <MyComponent />;
When this is passed to `React.render`, React will call the constructor for you and create a `ReactComponent`, which returned.
```javascript
var component = React.render(element, document.body);
var component = React.render(element, document.getElementById('example'));
```
If you keep calling `React.render` with the same type of `ReactElement` and the same container DOM `Element` it always returns the same instance. This instance is stateful.
```javascript
var componentA = React.render(<MyComponent />, document.body);
var componentB = React.render(<MyComponent />, document.body);
var componentA = React.render(<MyComponent />, document.getElementById('example'));
var componentB = React.render(<MyComponent />, document.getElementById('example'));
componentA === componentB; // true
```

View File

@@ -0,0 +1,147 @@
---
id: thinking-in-react-ko-KR
title: 리액트로 생각해보기
permalink: thinking-in-react-ko-KR.html
prev: tutorial-ko-KR.html
next: videos-ko-KR.html
---
이 문서의 원본은 [공식 블로그](/react/blog)의 [포스팅](/react/blog/2013/11/05/thinking-in-react.html) 입니다.
제가 생각하기에, React는 JavaScript로 크고 빠른 웹 애플리케이션을 만드는데 최고입니다. 페이스북과 인스타그램에서 우리에게 잘 맞도록 조정되어 왔습니다.
React의 많은 뛰어난 점들 중 하나는 생각을 하면서 애플리케이션을 만들게 한다는 겁니다. 이 포스트에서 React를 이용해 검색이 가능한 상품자료 테이블을 만드는 생각 과정을 이해할 수 있게 차근차근 설명할 겁니다.
## 모형으로 시작해보기
우리가 이미 JSON API와 디자이너로부터 넘겨받은 모형을 이미 가지고 있다고 생각해봅시다. 보시다시피 우리 디자이너는 별로 좋지 않습니다:
![Mockup](/react/img/blog/thinking-in-react-mock.png)
우리의 JSON API는 아래와 같은 데이터를 리턴합니다:
```
[
{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"}
];
```
## 1단계: UI를 계층 구조의 컴포넌트로 분쇄하세요.
당신이 하고싶은 첫번째는 모형에 있는 모든 컴포넌트 (그리고 자식엘리먼트) 주위에 상자를 그리고, 이름을 부여하는 것입니다. 만약 당신이 디자이너와 같이 작업중이라면, 그들은 이미 이 작업을 해놨을지도 모릅니다. 당장 가서 이야기해보세요. 그들의 포토샵 레이어 이름이 결국 당신의 React 컴포넌트들의 이름이 될 것입니다.
그런데 무엇이 컴포넌트가 되어야 할까요? 당신이 새로운 함수나 객체를 만들어야만 한다면, 똑같이 적용하세요. 한가지 방법은 [단일 책임의 원칙](http://ko.wikipedia.org/wiki/%EB%8B%A8%EC%9D%BC_%EC%B1%85%EC%9E%84_%EC%9B%90%EC%B9%99) 입니다. 즉 하나의 컴포넌트는 이상적으로 한가지 작업만 수행해야 합니다. 컴포넌트가 결국 커진다면 작은 자식 컴포넌트로 쪼개져야 합니다.
주로 JSON 데이터 모델을 사용자에게 보여주기 때문에, 자료 모델이 잘 설계 되었다면 UI(혹은 컴포넌트 구조)가 잘 맞아 떨어진다는 것을 알게 될 겁니다. UI와 자료 모델은 같은 *정보 설계구조*로 따라가는 경향이 있기 때문입니다. 즉, UI를 컴포넌트들로 쪼개는 작업은 크게 어렵지 않습니다. 확실하게 각각 하나의 부분이 되도록 쪼개세요.
![Component diagram](/react/img/blog/thinking-in-react-components.png)
이 간단한 애플리케이션에는 다섯개의 컴포넌트가 있습니다. 각 컴포넌트들이 대표하는 자료를 기울여 표기했습니다.
1. **`FilterableProductTable` (오렌지):** 예제 전부를 포함합니다.
2. **`SearchBar` (파랑):** 모든 *사용자 입력* 을 받습니다.
3. **`ProductTable` (초록):** *자료 모음*을 *사용자 입력*에 맞게 거르고 보여줍니다.
4. **`ProductCategoryRow` (청록):** 각 *카테고리*의 제목을 보여줍니다.
5. **`ProductRow` (빨강):** 각 *프로덕트*를 보여줍니다.
`ProductTable`을 보면 테이블 제목("Name", "Price" 라벨들을 포함한)은 컴포넌트가 아닌것을 알 수 있습니다. 이건 기호의 문제이고, 어느쪽으로 만들던 논쟁거리입니다. 예를 들어 저는 *자료 모음*을 그리는 `ProductTable`의 의무라고 생각했기 때문에 남겨 두었습니다. 하지만 이 제목이 복잡해진다면 (예를 들어 정렬을 추가할 여유가 있다거나 하는), 이건 확실히 `ProductTableHeader` 컴포넌트로 만드는 것이 맞을 겁니다.
이제 모형에 들어있는 컴포넌트들에 대해 알아보았으니, 계층 구조로 만들어 봅시다. 이건 쉽습니다. 다른 컴포넌트 속에 들어있는 컴포넌트를 자식으로 나타내기만 하면 됩니다.
* `FilterableProductTable`
* `SearchBar`
* `ProductTable`
* `ProductCategoryRow`
* `ProductRow`
## 2단계: 정적 버전을 만드세요.
<iframe width="100%" height="300" src="https://jsfiddle.net/reactjs/yun1vgqb/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
계층구조의 컴포넌트들을 가지고 있으니, 이젠 애플리케이션을 구현할 시간입니다. 가장 쉬운 방법은 상호작용을 하지 않는 채로 자료 모델을 이용해 UI를 그리는 것입니다. 정적 버전을 만드는 데에는 적은 생각과 많은 노동이 필요하고, 상호작용을 추가하는 데에는 많은 생각과 적은 노동이 필요하기 때문에 둘을 분리하는 것은 쉽습니다. 왜 그런지 봅시다.
자료 모델을 그리는 애플리케이션의 정적버전을 만들기 위해서, 다른 컴포넌트에 재사용할 컴포넌트를 만들고 자료 전달을 위해 *props*를 사용하고 싶을 것입니다. 만약 *상태*라는 개념에 익숙하다면, 정적 버전을 만들때 **절대 상태를 사용하지 마세요**. 상태는 오직 상호작용, 즉 가변적인 자료를 위해서만 준비되어 있습니다. 정적 버전을 만들 때는 필요가 없습니다.
껍데기부터 혹은 속알맹이부터 만들 수 있습니다. 즉 계층구조상 위에서부터 (`FilterableProductTable` 부터) 혹은 아래에서부터 (`ProductRow`), 어느 방향에서든 시작해도 됩니다. 통상 큰 프로젝트에서는 계층구조상 위에서부터 시작하는 것이 쉽고, 테스트를 작성할때는 아래에서부터 시작하는 것이 쉽습니다.
이 단계의 결과, 자료 모델을 그리는 재활용 가능한 컴포넌트의 라이브러리를 갖게 되었습니다. 정적버전 이후로 컴포넌트들은 오직 `render()` 메소드만 갖고 있습니다. 계층구조상 가장 위의 컴포넌트 (`FilterableProductTable`)은 자료 모델을 prop으로 취할 것입니다. 자료 모델이 변했을 때, `React.render()`를 다시 부르면 업데이트 됩니다. 어떻게 UI가 업데이트 되는지 참 알기 쉽습니다. 자료가 바뀌어도 처리해야 할 복잡한 일이 아무것도 없습니다. React의 **단일 방향 자료 흐름** (혹은 *단일방향 바인딩*)이 모든것을 모듈식으로, 추론하기 쉽게, 그리고 빠르게 유지해줍니다.
이 단계를 진행하는 데에 도움이 필요하시다면, [React 문서](/react/docs/getting-started-ko-KR.html)를 참조하세요.
### 잠시만: props vs state
React 에는 두가지 타입의 자료 "모델"이 있습니다: props 와 state. 두가지의 구분점을 이해하는데 매우 중요합니다; 혹시 차이점을 확신하지 못한다면 걷어내세요 [공식 문서](/react/docs/interactivity-and-dynamic-uis-ko-KR.html).
## 3단계: UI state 의 표현을 작지만 완전하도록 확인하세요.
상호적인 UI를 만들기 위해서는 자료 모델 변화에 반응할 수 있어야 합니다. React는 **state**로 이걸 쉽게 만들어주죠.
올바르게 애플리케이션을 만들기 위해서는 첫째로 애플리케이션에 필요한 변할 수 있는 state 들의 최소한의 집합에 대해서 생각해볼 필요가 있습니다. 여기 방법이 있습니다: *스스로 반복하지 마세요* (DRY). 애플리케이션의 상태를 나타낼 수 있는 가장 최소한의 표현 방식을 찾고, 그 밖의 것은 필요할 때 계산합니다. 예를들어 TODO 목록를 만든다고 칩시다. TODO 아이템들의 배열만 유지하세요; 갯수를 표현하기 위한 state 변수를 분리하지 마세요. 대신 TODO 아이템들 배열의 길이를 이용하세요.
예제 애플리케이션에서의 모든 자료유형에 대해 생각해 봅시다:
* product 들의 원본 목록
* 사용자가 입력한 검색어
* 체크박스의 값
* product 들의 필터된 목록
어느것이 state 가 될지 따져봅시다. 간단하게 각 자료에 대해 세가지만 생각해 보세요.
1. 만약 부모로부터 props 를 이용해 전달됩니까? 그렇다면 이건 state가 아닙니다.
2. 종종 바뀝니까? 아니라면 이것 역시 state가 아닙니다.
3. 컴포넌트에 있는 다른 state나 props를 통해서 계산되어질 수 있습니까? 역시 state가 아닙니다.
product 들의 원본 목록은 props를 통해서 전달되기 때문에, state가 아닙니다. 검색어와 체크박스의 값은 다른것에 의해 계산될 수 있는 값이 아니고, 시시각각 변하기때문에 state가 맞습니다. 마지막으로 product 들의 걸러진 목록 역시 state가 아닙니다. 원본 목록과 검색어, 체크박스의 값 등에 의해 연산되어지는 값이기 때문이죠.
결국, state는 다음과 같습니다:
* 사용자가 입력한 검색어
* 체크박스의 값
## 4단계: 어디서 state가 유지되어야 하는지 확인하세요.
<iframe width="100%" height="300" src="https://jsfiddle.net/reactjs/zafjbw1e/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
이제 최소한의 state가 무엇인지 알아냈습니다. 다음은 어떤 컴포넌트가 이 state를 변형하거나 만들어낼지 알아내야 합니다.
기억하세요: React는 계층적 아래 컴포넌트로만 향하는 단일방향성 자료 흐름을 가집니다. 지금당장은 어떤 컴포넌트가 자기 자신의 state를 가져야 할지 명확하지 않을 것입니다. **이것이 초심자가 가장 이해하기 어려운 부분입니다**. 이제 개념을 명확히 하기 위해 다음으로 따라가 봅시다:
애플리케이션에서 state의 경우:
* 모든 컴포넌트가 state를 통해 무언가를 그려냅니다.
* 대표 컴포넌트가 뭔지 찾으세요 (계층적으로 다른 컴포넌트들의 단일 상위 컴포넌트는 state를 가질 필요가 있습니다).
* 대표 컴포넌트 혹은 또다른 컴포넌트는 가능한 상위의 컴포넌트가 state를 소유해야 합니다.
* 만약 state를 가져야할 컴포넌트가 어느 것인지 모르겠으면, 새로운 컴포넌트를 만들어 state를 부여하고 기존의 대표 컴포넌트 위에 추가하세요.
이 전략을 우리 애플리케이션에 적용해 봅시다.
* `ProductTable`은 state에 대해 걸러질 필요가 있고, `SearchBar` 역시 검색어 state와 체크박스 state를 보여줄 필요가 있습니다.
* 대표 컴포넌트는 `FilterableProductTable` 입니다.
* 개념적으로 검색어와 체크박스 값은 `FilterableProductTable`에 있어야 한다는 것이 명확합니다.
좋습니다. state를 `FilterableProductTable`에서 관리하도록 결정했습니다. 먼저 `getInitialState()` 메소드를 `FilterableProductTable`에 추가하세요. 이 메소드는 애플리케이션의 초기 state를 갖도록 `{filterText: '', inStockOnly: false}`를 리턴하면 됩니다. 그리고 `filterText``inStockOnly``ProductTable``SearchBar`에 prop으로 전달하세요. 마지막으로 이 prop들을 `ProductTable`을 걸러내는 데, 그리고 `SearchBar` form fields의 값을 세팅하는데 사용하세요.
이제 어떻게 애플리케이션이 동작하는지 볼 수 있습니다: `filterText``"ball"`로 설정하고 업데이트합니다. 자료 테이블이 제대로 업데이트 되는 것을 볼 수 있을 겁니다.
## 5단계: 반대방향 자료 흐름을 추가하세요.
<iframe width="100%" height="300" src="https://jsfiddle.net/reactjs/n47gckhr/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
앞서 우리는 계층적으로 아랫방향 흐름의 props, state전달로 잘 동작하는 애플리케이션을 만들었습니다. 이제 다른방향의 자료 흐름을 지원할 시간입니다: form 컴포넌트들은 `FilterableProductTable`의 state를 업데이트할 필요성이 있죠.
React는 어떻게 이 프로그램이 동작하는지 이해하기 쉽게 이 자료의 흐름을 명시적으로 만들어주지만 전통적인 두 방향의 자료 바인딩보다 다소 입력할 것이 많습니다. React는 이러한 패턴을 양방향 바인딩처럼 편하게 사용할 수 있도록 ReactLink를 제공하지만, 이 글의 목적상 명시적인 방식만 사용했습니다.
지금 예제에 문자열을 입력하거나 체크박스를 체크하더라도 React가 입력을 무시하는것을 볼 수 있습니다. 의도적으로 `input`의 prop에 `value`를 세팅하면 항상 `state``FilterableProductTable`로부터 전달되어야 합니다.
우리가 원하는 것이 무엇인지 생각해 봅시다. 사용자가 form을 바꿀때마다 사용자 입력을 반영하기 위해 업데이트 하기를 원하죠. 컴포넌트들이 오직 자기 자신의 state만 업데이트 하더라도 `FilterableProductTable`은 state가 변할때마다 반영되어야할 `SearchBar`에 콜백을 전달할 것입니다. 이 알림을 위해서 `onChange`이벤트를 사용할 수 있습니다. 그리고 `FilterableProductTable`으로부터 전달된 콜백은 `setState()`를 호출할 것이고, 애플리케이션은 업데이트될 것입니다.
많은 코드가 필요한 것 같이 들릴 수 있지만 실제로는 몇 줄 되지 않습니다. 그리고 애플리케이션의 구석구석에서 데이터가 어떻게 흐르는지 매우 명확해집니다.
## 그리고
이 글이 컴포넌트와 React로 애플리케이션을 어떻게 만들지에 대한 아이디어가 되길 바랍니다. 원래 하던 방식보다 조금 타이핑을 더 해야할지도 모르지만, 코드는 쓰는 경우보다 읽히는 경우가 많다는 점, 매우 읽기 편하고 명시적인 코드를 썼다는 점을 기억하세요. 컴포넌트로 큰 라이브러리를 만들기 시작할 때, 이 명시성과 모듈성에 감사하게 될 것이며 재사용함에 따라 코드의 양도 줄어들 것입니다. :)

701
docs/docs/tutorial.ja-JP.md Normal file
View File

@@ -0,0 +1,701 @@
---
id: tutorial-ja-JP
title: チュートリアル
prev: getting-started-ja-JP.html
next: thinking-in-react-ja-JP.html
---
これから、シンプルながらも現実的なコメントボックスを作ってみましょう。ブログにも設置できるようなもので、Disqus や LiveFyre、Facebook comments が採用しているリアルタイムコメントの基本機能を備えたものを想定しています。
その機能とは次のようなものです。
* コメント全件の表示欄
* コメントの送信フォーム
* 自作のバックエンドとの連携機能
ついでに小洒落た機能もいくつか加えましょう。
* **コメントの先読み:** 送信したコメントをサーバに保存される前に表示させることで、アプリ動作の体感速度をアップさせます。
* **自動更新:** 他のユーザのコメントをリアルタイムで表示させます。
* **Markdown 記法:** ユーザが Markdown 記法でコメントを書けるようにします。
### 全部飛ばしてソースを見たいんだけど?
[全部 GitHub にあります。](https://github.com/reactjs/react-tutorial)
### サーバを動かす
このチュートリアルを始めるにあたっては必要ないですが、後半ではサーバに POST を投げる機能を追加します。サーバのことは良く知っていて自分でサーバを建てたいのであれば、それでも構いません。そうではないけれども、サーバサイドは考えずに React のことだけに焦点を絞って学びたい方のため、シンプルなサーバのソースコードを書いておきました。言語は JavaScript Node.jsまたは Python、Ruby、Go、ないし PHP で用意してあり、すべて GitHub にあります。[ソースを見る](https://github.com/reactjs/react-tutorial/) ことも出来ますし、 [zip ファイルでダウンロード](https://github.com/reactjs/react-tutorial/archive/master.zip)することも出来ます。
それでは最初のチュートリアルとして、`public/index.html` の編集から始めましょう。
### 始めてみましょう
このチュートリアルでは、あらかじめビルドされた JavaScript ファイルを CDN から読み込むことになります。自分の好きなエディタを立ち上げて、次のように新規の HTML ドキュメントを作りましょう。
```html
<!-- index.html -->
<html>
<head>
<title>Hello React</title>
<script src="https://fb.me/react-{{site.react_version}}.js"></script>
<script src="https://fb.me/JSXTransformer-{{site.react_version}}.js"></script>
<script src="https://code.jquery.com/jquery-1.10.0.min.js"></script>
</head>
<body>
<div id="content"></div>
<script type="text/jsx">
// ここにコードが入ります
</script>
</body>
</html>
```
このチュートリアルに関しては、JavaScript コードを script タグの中へ書いていくことにします。
> 確認:
>
> 上のコードで jQuery を読み込んでいますが、これはチュートリアル後半で ajax のコードを簡潔に書きたいだけなので、React を動かすのに必要なものでは**ありません**。
### 最初のコンポーネント
React はすべて、モジュール単位で組み立てられるcomposableコンポーネントからなっています。今回取り上げるコメントボックスの例では、以下のようなコンポーネント構造をとります。
```
- CommentBox
- CommentList
- Comment
- CommentForm
```
それではまず `CommentBox` コンポーネントから作っていきましょう。とは言っても単なる `<div>` です。
```javascript
// tutorial1.js
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
Hello, world! I am a CommentBox.
</div>
);
}
});
React.render(
<CommentBox />,
document.getElementById('content')
);
```
#### JSX シンタックス
先程書いた JavaScript の中に、XMLに似たシンタックスがあることに気付いたでしょうか。このシンタックスシュガーは、シンプルなプリコンパイラによって次のような生の JavaScript に変換されます。
```javascript
// tutorial1-raw.js
var CommentBox = React.createClass({displayName: 'CommentBox',
render: function() {
return (
React.createElement('div', {className: "commentBox"},
"Hello, world! I am a CommentBox."
)
);
}
});
React.render(
React.createElement(CommentBox, null),
document.getElementById('content')
);
```
どちらを採るかは自由ですが、生の JavaScript よりも JSX シンタックスのほうが扱いやすいと考えています。詳しくは [JSX シンタックスの記事](/react/docs/jsx-in-depth.html) を読んでみてください。
#### 何をしているのか
先程のコードでは、とあるメソッドを持った JavaScript オブジェクトを `React.createClass()` に渡しています。これは新しい React コンポーネントを作るためです。このメソッドは `render` と呼ばれており、最終的に HTML へレンダリングされる React コンポーネントのツリーを返す点が肝になります。
コードに書いた `<div>` タグは実際の DOM ノードではありません。これは React の `div` コンポーネントのインスタンスです。 これらは React が理解できるマーカーやデータの一部だと見なせます。React は **安全** です。デフォルトで XSS 対策を行っているので、HTML 文字列を生成することはありません。
実際の HTML を返す必要はありません。 自分が(もしくは他の誰かが)組み立てたコンポーネントツリーを返せばいいのです。 これこそ React が **composable**な(組み立てられる)ものである理由であり、この大事なルールを守ればフロントエンドはメンテナンスしやすいものとなります。
`React.render()` はまずルートコンポーネントのインスタンスを作り、フレームワークを立ち上げます。そして、第2引数で与えられた実際の DOM 要素にマークアップを挿入します。
## コンポーネントの組み立て
それでは `CommentList``CommentForm` の骨組みを作りましょう。繰り返しになりますが、これらはただの `<div>` です。
```javascript
// tutorial2.js
var CommentList = React.createClass({
render: function() {
return (
<div className="commentList">
Hello, world! I am a CommentList.
</div>
);
}
});
var CommentForm = React.createClass({
render: function() {
return (
<div className="commentForm">
Hello, world! I am a CommentForm.
</div>
);
}
});
```
さて、この新しいコンポーネントを使えるように `CommentBox` コンポーネントを書き直しましょう。
```javascript{6-8}
// tutorial3.js
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList />
<CommentForm />
</div>
);
}
});
```
ここで、HTML タグと組み立てているコンポーネントが、どのようにミックスされているかを確認しましょう。 HTML コンポーネントは既定の React コンポーネントですが、自分で定義したもの同士はそれぞれ別物になります。JSX コンパイラは HTML タグを自動的に `React.createElement(tagName)` の式に書き換え、それぞれを別々のものに変換します。これはグローバルの名前空間が汚染させるのを防ぐためです。
### Props を使う
次のステップは `Comment` コンポーネントの作成です。このコンポーネントは、自分の親にあたるコンポーネントから渡されたデータを扱います。親から渡されたデータは、子のコンポーネントで「プロパティ」として利用できます。この「プロパティ」には `this.props` を通してアクセスします。propsプロパティを使うと `CommentList` から `Comment` に渡されたデータの読み込み、マークアップのレンダリングが可能になります。
```javascript
// tutorial4.js
var Comment = React.createClass({
render: function() {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
{this.props.children}
</div>
);
}
});
```
JSX の内側で属性値または子要素としてJavaScript の式を波括弧で囲むと、テキストや React コンポーネントをツリーに加えることが出来ます。コンポーネントに渡された属性値には名前が付けられており、`this.props` をキーとしてアクセスできます。また、ネストされた子要素の値は `this.props.children` でアクセスが可能です。
### コンポーネントのプロパティ
さて、これまでに `Comment` コンポーネントを定義しました。これからこのコンポーネントに、コメントの著者名と内容を渡せるようにします。これを実装することで、それぞれ別のコメントに対して同じコードを使い回せるようになります。それでは早速 `CommentList` の中にコメントを追加していきましょう。
```javascript{6-7}
// tutorial5.js
var CommentList = React.createClass({
render: function() {
return (
<div className="commentList">
<Comment author="Pete Hunt">This is one comment</Comment>
<Comment author="Jordan Walke">This is *another* comment</Comment>
</div>
);
}
});
```
ここで確認してもらいたいのは、親の `CommentList` コンポーネントから、子の `Comment` コンポーネントにデータが渡されている点です。この例ではまず、*Pete Hunt*(属性値を通して)と *This is one comment*XML のような子ノードを通して)といったデータを `Comment` コンポーネントに渡しています。少し前に確認した通り、`Comment` コンポーネントからこれらの「プロパティ」にアクセスするには、`this.props.author` と `this.props.children` を使います。
### Markdown の追加
Markdown はインラインでテキストをフォーマットする簡単な記法です。例えば、テキストをアスタリスクで挟むと強調されて表示されます。
まず最初に、サードパーティ製の **Showdown** ライブラリをアプリケーションに追加します。 Showdown は Markdown テキストを生の HTML に変換する JavaScript ライブラリです。 既にある head タグの内側に script タグを書き込み、以下のように Showdown を読み込ませます。
```html{7}
<!-- index.html -->
<head>
<title>Hello React</title>
<script src="https://fb.me/react-{{site.react_version}}.js"></script>
<script src="https://fb.me/JSXTransformer-{{site.react_version}}.js"></script>
<script src="https://code.jquery.com/jquery-1.10.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
</head>
```
次に、Markdown で書かれたコメントを変換して出力してみましょう。
```javascript{2,10}
// tutorial6.js
var converter = new Showdown.converter();
var Comment = React.createClass({
render: function() {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
{converter.makeHtml(this.props.children.toString())}
</div>
);
}
});
```
このコードでは Showdown のライブラリを呼び出すことしかしていません。`this.props.children` は React によってラップされたテキストですが、これを Showdown が理解できる生の文字列に変換する必要があります。そのため、上のコードでは明示的に `toString()` を呼び出しているのです。
しかし問題があります!ブラウザがレンダリングしたコメントは次のように表示されているはずです -- "`<p>`This is `<em>`another`</em>` comment`</p>`" このようなタグは実際に HTML としてレンダリングさせたいですね。
このような現象が起きるのは React が XSS 攻撃に対する防御を行っているからです。これを回避する方法はありますが、それを使うときにはフレームワークが警告をします。
```javascript{5,11}
// tutorial7.js
var converter = new Showdown.converter();
var Comment = React.createClass({
render: function() {
var rawMarkup = converter.makeHtml(this.props.children.toString());
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<span dangerouslySetInnerHTML={{"{{"}}__html: rawMarkup}} />
</div>
);
}
});
```
これは特別な API であり、生の HTML が挿入されにくくなるよう意図的に作ったものです。しかし、ここでは Showdown のためにこのバックドアを利用しています。
**注意:** この機能を使うことで、Showdown は安全なものと信頼することになります。
### データモデルとの連携
これまではソースコードにコメントを直に書き込んでいました。その代わりに、これからは JSON の blob データをコメントリストにレンダリングしてみましょう。サーバからデータを取得するのが最後の目標ですが、とりあえず今はソースコードの中にデータを書いておくことにします。
```javascript
// tutorial8.js
var data = [
{author: "Pete Hunt", text: "This is one comment"},
{author: "Jordan Walke", text: "This is *another* comment"}
];
```
このデータはモジュールを使って `CommentList` に取り込む必要があります。`CommentBox` の `React.render()` の部分を手直しして、props を通してデータが `CommentList` へ渡るようにしましょう。
```javascript{7,15}
// tutorial9.js
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.props.data} />
<CommentForm />
</div>
);
}
});
React.render(
<CommentBox data={data} />,
document.getElementById('content')
);
```
こうして `CommentList` がデータを扱えるようになりました。それでは、コメントを動的にレンダリングしてみましょう。
```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 (
<div className="commentList">
{commentNodes}
</div>
);
}
});
```
これだけ!
### サーバからのデータの取得
続いて、ハードコーディングしていたデータを、サーバからの動的なデータに置き換えてみましょう。
```javascript{3}
// tutorial11.js
React.render(
<CommentBox url="comments.json" />,
document.getElementById('content')
);
```
このコンポーネントは自身を再びレンダリングすることになるので、これまでのコンポーネントとは異なります。レスポンスがサーバから返ってくると、送られてきた新しいコメントをコンポーネントがレンダリングすることになります。ですが、その時点までコンポーネントには何もデータがないはずです。
### Reactive state
これまで、それぞれのコンポーネントは自身の props の値を用いて、一度だけレンダリングしていました。`props` はイミュータブルです。つまり、props は親から渡されますが、同時に props は親の「所有物」なのです。データが相互にやり取りされるのを実現するため、ここでミュータブルな **state**(状態)をコンポーネントに取り入れましょう。コンポーネントは `this.state` というプライベートな値を持ち、`this.setState()` を呼び出すことで state を更新することが出来ます。コンポーネントの state が更新されれば、そのコンポーネントは自身を再びレンダリングし直します。
`render()` メソッドは `this.props` や `this.state` と同じく宣言的に書かれています。このフレームワークによって、UI と入力が常に一致するようになります。
サーバがデータを集めてくれば、今あるコメントのデータを更新することになるかもしれません。state を表すコメントのデータの配列を `CommentBox` コンポーネントに加えましょう。
```javascript{3-5,10}
// tutorial12.js
var CommentBox = React.createClass({
getInitialState: function() {
return {data: []};
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
});
```
`getInitialState()` メソッドはコンポーネントのライフサイクル内で一回だけ実行され、コンポーネントの state における初期値を設定します。
#### State の更新
コンポーネントの作成と同時に、サーバから JSON データを GET で取得し、state を更新して最新のデータを反映させてみましょう。実際のアプリケーションでは動的なエンドポイントになるでしょうが、今回の例では話を簡単にするため、以下の静的な JSON ファイルを使います。
```javascript
// tutorial13.json
[
{"author": "Pete Hunt", "text": "This is one comment"},
{"author": "Jordan Walke", "text": "This is *another* comment"}
]
```
サーバへの非同期リクエストを作るため、ここでは jQuery を使います。
注意: ここからは AJAX アプリケーションを作っていくので、自分のファイルシステム上ではなく Web サーバを使ってアプリを作る必要があります。残りのチュートリアルに必要な機能は [冒頭で紹介した](#running-a-server) サーバに含まれています。ソースコードは [GitHub に](https://github.com/reactjs/react-tutorial/)用意してあります。
```javascript{6-17}
// tutorial13.js
var CommentBox = React.createClass({
getInitialState: function() {
return {data: []};
},
componentDidMount: 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)
});
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
});
```
さて、`componentDidMount` はコンポーネントがレンダリングされたときに React が自動的に呼び出すメソッドです。動的な更新の鍵となるのは `this.setState()` の呼び出し方です。ここでは、古いコメントの配列をサーバから取ってきた新しい配列に置き換え、UI を自動的に更新させてみましょう。このような reactivity反応性・柔軟性のおかげで、リアルタイム更新を最小限にすることが出来ます。次のコードではシンプルなポーリングをしていますが、WebSockets や他の方法でも簡単に実現できます。
```javascript{3,14,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)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
});
React.render(
<CommentBox url="comments.json" pollInterval={2000} />,
document.getElementById('content')
);
```
ここまでに、AJAX を呼び出す部分を別のメソッド内に移動させました。加えて、コンポーネントが最初に読み込まれてから2秒ごとに AJAX のメソッドが呼び出されるようにしました。ぜひ自分のブラウザで実行させて、`comments.json` ファイルに変更を加えてみてください。2秒以内に表示が更新されるはずです
### 新しいコメントの追加
いよいよフォームを作る段階に来ました。ここで `CommentForm` コンポーネントは、ユーザに自分の名前とコメントの内容を入力させ、コメントを保存させるためにサーバへリクエストを送る役割を果たすことになります。
```javascript{5-9}
// tutorial15.js
var CommentForm = React.createClass({
render: function() {
return (
<form className="commentForm">
<input type="text" placeholder="Your name" />
<input type="text" placeholder="Say something..." />
<input type="submit" value="Post" />
</form>
);
}
});
```
それでは、フォームを使ってデータをやり取りできるようにしましょう。ユーザがフォームから送信したら、フォームをクリアしてサーバにリクエストを送り、コメントリストをリフレッシュすることになります。まず手始めに、フォームからの送信イベントを受け取ってフォームをクリアできるようにしましょう。
```javascript{3-13,16-19}
// tutorial16.js
var CommentForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var author = React.findDOMNode(this.refs.author).value.trim();
var text = React.findDOMNode(this.refs.text).value.trim();
if (!text || !author) {
return;
}
// TODO: サーバにリクエストを送信
React.findDOMNode(this.refs.author).value = '';
React.findDOMNode(this.refs.text).value = '';
return;
},
render: function() {
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="submit" value="Post" />
</form>
);
}
});
```
##### イベント
React がコンポーネントにイベントハンドラを登録する際は camelCase の命名規則に従います。上のコードではフォームに `onSubmit` ハンドラを登録し、フォームから妥当な入力が送信されたらフォームをクリアするようになっています。
また `preventDefault()` を呼び出しているので、フォームからの送信に対してブラウザのデフォルト処理が反応することはありません。
##### Refs
先程のコードでは `ref` 属性値を使って子のコンポーネントに名前を付けており、`this.ref` でそのコンポーネントを参照しています。`React.findDOMNode(component)` にコンポーネントを指定して呼び出すことで、ブラウザの持つ実際の DOM 要素を取得することが出来ます。
##### Props としてのコールバック
ユーザがコメントを送信したら、コメントリストをリフレッシュして新しいリストを読み込むことになります。コメントリストを表す state を保持しているのは `CommentBox` なので、必要なロジックは `CommentBox` の中に書くのが筋でしょう。
ここでは子のコンポーネントから親に向かって、いつもとは逆方向にデータを返す必要があります。まず、親のコンポーネントに新しいコールバック関数(`handleCommentSubmit`)を定義します。続いて `render` メソッド内にある子のコンポーネントにコールバックを渡すことで、`onCommentSubmit` イベントとコールバックを結び付けています。こうすることで、イベントが発生するたびにコールバックが呼び出されます。
```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)
});
},
handleCommentSubmit: function(comment) {
// TODO: サーバに送信、リストをリフレッシュ
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});
```
それでは、ユーザがフォームから送信したら `CommentForm` がコールバックを呼び出せるようにしましょう。
```javascript{10}
// tutorial18.js
var CommentForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var author = React.findDOMNode(this.refs.author).value.trim();
var text = React.findDOMNode(this.refs.text).value.trim();
if (!text || !author) {
return;
}
this.props.onCommentSubmit({author: author, text: text});
React.findDOMNode(this.refs.author).value = '';
React.findDOMNode(this.refs.text).value = '';
return;
},
render: function() {
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="submit" value="Post" />
</form>
);
}
});
```
こうしてコールバックが出来たので、あとはサーバにコメントを送信してリストをリフレッシュすれば完璧です。
```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)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});
```
### 最適化: 先読み更新
アプリケーションに必要な機能は一通り実装できました。しかし、フォームからコメントを送信しても、サーバからのレスポンスが来るまで自分のコメントはリストに載らないため、アプリの動作は遅く感じます。ここでは、送信したコメントをリストに先読みさせて、アプリの体感速度をアップさせましょう。
```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)
});
},
handleCommentSubmit: function(comment) {
var comments = this.state.data;
var newComments = comments.concat([comment]);
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)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});
```
### おめでとう!
シンプルな手順を追ううちにコメントボックスを作ることが出来ました。さらに詳しいことは[なぜ React を使うのか](/react/docs/why-react.html)を読んだり、[API リファレンス](/react/docs/top-level-api.html)を開いたりしてハッキングを始めましょう!幸運を祈ります!

702
docs/docs/tutorial.ko-KR.md Normal file
View File

@@ -0,0 +1,702 @@
---
id: tutorial-ko-KR
title: 튜토리얼
permalink: tutorial-ko-KR.html
prev: getting-started-ko-KR.html
next: thinking-in-react-ko-KR.html
---
블로그에 붙일만한 간단하지만 실용적인 댓글상자를 만들어 볼 것입니다. Disqus, LiveFyre, Facebook에서 제공하는 것 같은 실시간 댓글의 간단한 버전이죠.
이런 기능을 넣겠습니다:
* 댓글목록
* 댓글작성폼
* 커스텀 백엔드를 위한 Hooks
멋진 기능도 조금 넣어보겠습니다:
* **낙관적 댓글 달기:** 댓글은 서버에 저장되기도 전에 목록에 나타납니다. 그래서 빠르게 느껴집니다.
* **실시간 업데이트:** 다른 사용자가 남기는 댓글이 실시간으로 나타납니다.
* **Markdown 지원:** 사용자는 글을 꾸미기 위해 Markdown 형식을 사용할 수 있습니다.
### 그냥 다 생략하고 소스만 보고 싶나요?
[GitHub에 전부 있습니다.](https://github.com/reactjs/react-tutorial)
### 서버 구동하기
이 튜토리얼을 시작할 때 필요한 건 아니지만, 나중에 실행 중인 서버에 `POST` 요청을 하는 기능을 추가하게 될 것입니다. 서버를 구성하는 것이 익숙하다면, 본인이 편한 방식대로 서버를 구성해 주세요. 서버사이드에 대한 고민없이 React의 학습 그 자체에 집중하고 싶은 분들을 위해서, 몇 가지 언어로 간단한 서버코드를 작성해 놓았습니다 - JavaScript (Node.js), Python, Ruby, Go, PHP 버전이 있고, GitHub에서 찾아보실 수 있습니다. [소스를 확인](https://github.com/reactjs/react-tutorial/)하거나 [zip 파일을 다운로드](https://github.com/reactjs/react-tutorial/archive/master.zip)하고 시작하세요.
튜토리얼을 시작하려면, `public/index.html`을 열고 바로 시작하세요.
### 시작하기
이 튜토리얼에서는 CDN에 있는 미리 빌드된 JavaScript 파일들을 사용합니다. 선호하는 에디터를 열어, 새로운 HTML 문서를 만드세요:
```html
<!-- index.html -->
<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="https://code.jquery.com/jquery-2.1.3.min.js"></script>
</head>
<body>
<div id="content"></div>
<script type="text/jsx">
// 여기에 코드를 작성합니다
</script>
</body>
</html>
```
다음 진행을 위해, 위의 스크립트 태그안에 JavaScript 코드를 작성합니다.
> 주의:
>
> 여기서는 ajax 요청 코드를 단순화 하기 위해 jQuery를 넣었지만, 이는 React의 동작에 필수적인 것은 **아닙니다**.
### 첫 번째 컴포넌트
모듈화 된, 조합가능한 컴포넌트가 React의 전부입니다. 댓글상자 예제에서 우리는 다음과 같은 컴포넌트 구조를 가질 것입니다:
```
- CommentBox
- CommentList
- Comment
- CommentForm
```
자, 이제 `CommentBox` 컴포넌트를 만들어 봅시다. `<div>` 하나로 구성되어 있습니다.
```javascript
// tutorial1.js
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
Hello, world! I am a CommentBox.
</div>
);
}
});
React.render(
<CommentBox />,
document.getElementById('content')
);
```
#### JSX 문법
JavsScript 안의 유사 XML 구문이 먼저 눈에 띌 것입니다. 우리에겐 이를 JavaScript로 변환해주는 간단한 프리컴파일러(precompiler)가 있습니다.
```javascript
// tutorial1-raw.js
var CommentBox = React.createClass({displayName: 'CommentBox',
render: function() {
return (
React.createElement('div', {className: "commentBox"},
"Hello, world! I am a CommentBox."
)
);
}
});
React.render(
React.createElement(CommentBox, null),
document.getElementById('content')
);
```
JSX의 사용은 선택적이지만 JSX 문법이 일반 JavsScript보다 사용하기 쉽습니다. [JSX 문법 문서](/react/docs/jsx-in-depth.html)에서 더 알아보세요.
#### 무슨 일이 일어나고 있는가
우리는 새로운 React 컴포넌트를 만들기 위해 `React.createClass()`로 JavaScript 객체에 몇 개의 메소드를 담아 넘겼습니다. 이 중 가장 중요한것은 `render` 메소드인데, 이는 React 컴포넌트 트리를 리턴해서 최종적으로 실제 HTML을 그려주게 됩니다.
`<div>` 태그들은 실제 DOM 노드가 아니라 React `div` 컴포넌트의 인스턴스입니다. 이것은 React가 다룰 수 있는 데이터의 표시자(markers)나 조각이라 생각하셔도 됩니다. React는 **안전합니다**. 생(raw) HTML 문자열을 생성하는 것이 아니기 때문에 XSS을 기본적으로 방지합니다.
일반적인 HTML만 리턴할 수 있는 것은 아닙니다. 여러분이 직접 만든 (또는 다른 사람들이 만들어 놓은) 컴포넌트의 트리를 리턴할 수도 있습니다. 이것이 React를 **조합가능(composable)하게 만듭니다**: 유지보수 가능한 프론트엔드를 위한 핵심 교리(key tenet)지요.
`React.render()`는 최상위 컴포넌트의 인스턴스를 만들고, 두 번째 인수로 전달받은 DOM 엘리먼트에 마크업을 삽입해 프레임워크를 시작합니다.
## 컴포넌트 조합하기
이제 `CommentList``CommentForm`을 위한 뼈대를 구축해 봅시다. 이전과 마찬가지로 단순히 `<div>` 태그 하나 입니다.
```javascript
// tutorial2.js
var CommentList = React.createClass({
render: function() {
return (
<div className="commentList">
안녕! 댓글목록이야.
</div>
);
}
});
var CommentForm = React.createClass({
render: function() {
return (
<div className="commentForm">
안녕! 댓글 폼이야.
</div>
);
}
});
```
다음은 `CommentBox` 컴포넌트가 새로 만든 컴포넌트들을 사용하도록 수정합니다.
```javascript{6-8}
// tutorial3.js
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
<h1>댓글</h1>
<CommentList />
<CommentForm />
</div>
);
}
});
```
방금 만든 컴포넌트들을 어떻게 HTML 태그들과 섞어 사용하는지 살펴보세요. HTML 컴포넌트들도 한가지 차이만 제외한다면 우리가 정의한 것과 같은 표준적인 React 컴포넌트입니다. JSX 컴파일러가 자동으로 HTML 태그들을 `React.createElement(tagName)` 표현식으로 재작성하고 나머지는 그대로 둘 것입니다. 이는 전역 네임스페이스가 오염되는 것을 막아줍니다.
### props 사용하기
부모로 부터 받은 데이터에 의존하는 `Comment` 컴포넌트를 만들어 봅시다. 부모 컴포넌트로 부터 받은 데이터는 자식 컴포넌트에서 '프로퍼티'로 사용가능 합니다. 이 '프로퍼티들'은 `this.props`를 통해 접근합니다. props를 사용해 `CommentList`에서 전달받은 데이터를 읽어들이고, 마크업을 렌더할 수 있을 것입니다.
```javascript
// tutorial4.js
var Comment = React.createClass({
render: function() {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
{this.props.children}
</div>
);
}
});
```
JSX 내부의 중괄호로 둘러싸인 JavaScript 표현식(어트리뷰트나 엘리먼트의 자식으로 사용된)을 통해 텍스트나 React 컴포넌트를 트리에 더할 수 있습니다. `this.props`를 통해 컴포넌트에 전달된 특정한 어트리뷰트들에, `this.props.children`을 통해 중첩된 엘리먼트들에 접근할 수 있습니다.
### 컴포넌트 프로퍼티 (Component Properties)
`Comment` 컴포넌트를 만들었으니, 여기에 글쓴이와 내용을 넘겨보도록 합시다. 이렇게 함으로써 각 고유한 comment에서 같은 코드를 재사용할 수 있습니다. 먼저 댓글 몇 개를 `CommentList`에 추가해 봅시다:
```javascript{6-7}
// tutorial5.js
var CommentList = React.createClass({
render: function() {
return (
<div className="commentList">
<Comment author="Pete Hunt">댓글입니다</Comment>
<Comment author="Jordan Walke">*또 다른* 댓글입니다</Comment>
</div>
);
}
});
```
부모 컴포넌트인 `CommentList`에서 자식 컴포넌트인 `Comment`에 데이터들을 전달하고 있는것을 확인할 수 있습니다. 예를 들어, 우리는 어트리뷰트로 *Pete Hunt*를, XML 형식의 자식 노드로 *댓글입니다*를 첫 번째 `Comment`로 넘겼습니다. 위에서 언급했듯이 `Comment` 컴포넌트는 그들의 '프로퍼티'를 `this.props.author`, `this.props.children`를 통해 접근합니다.
### Markdown 추가하기
Markdown은 텍스트를 포맷팅하는 간단한 방식입니다. 예를 들어, 별표(`*`)로 텍스트를 둘러싸는 것은 강조의 의미입니다.
먼저 서드파티 라이브러리인 **marked**를 애플리케이션에 추가합니다. 이 JavaScript 라이브러리는 Markdown 텍스트를 HTML 문법으로 변환해줍니다. head 태그안에 스크립트 태그를 추가해 주세요. (React playground에는 이미 포함되어 있습니다):
```html{7}
<!-- index.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="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>
</head>
```
다음은, 댓글 텍스트를 Markdown으로 전환하고 출력해 봅시다.
```javascript{9}
// tutorial6.js
var Comment = React.createClass({
render: function() {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
{marked(this.props.children.toString())}
</div>
);
}
});
```
우리가 한 일이라고는 marked 라이브러리를 호출한 것 뿐입니다. marked가 `this.props.children`에서 텍스트를 읽어들여 처리할 수 있도록 React 형식의 텍스트(React's wrapped text)를 단순 텍스트(raw string)으로 전환하기 위해 명시적으로 `toString()`을 호출했습니다.
하지만 여기엔 문제가 있습니다! 우리는 HTML 태그들이 정상적으로 렌더되길 원하지만 브라우저에 출력된 결과물은 "`<p>``<em>`또 다른`</em>` 댓글입니다`</p>`"처럼 태그가 그대로 보일것입니다.
React는 이런 식으로 XSS 공격을 예방합니다. 우회할 방법이 있긴 하지만 프레임워크는 사용하지 않도록 경고하고 있습니다:
```javascript{4,10}
// tutorial7.js
var Comment = React.createClass({
render: function() {
var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<span dangerouslySetInnerHTML={{"{{"}}__html: rawMarkup}} />
</div>
);
}
});
```
이는 의도적으로 생(raw) HTML을 넣기 힘들게 하려고 만든 특별한 API지만 marked를 사용하기 위해 이 백도어를 활용합시다.
**잊지 마세요:** 이 기능은 marked가 안전한 것으로 믿고 사용하는 것입니다. 이 경우, 소스에 있는 그대로 넘겨 주는 대신, 모든 HTML 마크업을 이스케이프하도록 marked에게 `sanitize: true`를 넘겨 주었습니다.
### 데이터 모델 연결하기
지금까지는 소스코드에 직접 댓글을 넣었습니다. 이제부터는 JSON 데이터 덩어리를 댓글 목록에 렌더해보겠습니다. 최종적으로는 서버에서 데이터가 내려오겠지만, 지금은 소스에 직접 데이터를 넣어봅시다:
```javascript
// tutorial8.js
var data = [
{author: "Pete Hunt", text: "댓글입니다"},
{author: "Jordan Walke", text: "*또 다른* 댓글입니다"}
];
```
이 데이터를 모듈화된 방식으로 `CommentList`에 넣어야 합니다. props을 이용해 데이터를 넘기도록 `CommentBox`와 `React.render()` 호출 코드를 수정합시다.
```javascript{7,15}
// tutorial9.js
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
<h1>댓글</h1>
<CommentList data={this.props.data} />
<CommentForm />
</div>
);
}
});
React.render(
<CommentBox data={data} />,
document.getElementById('content')
);
```
이제 `CommentList`에서 데이터를 다룰 수 있습니다. 댓글을 동적으로 렌더해봅시다:
```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 (
<div className="commentList">
{commentNodes}
</div>
);
}
});
```
이게 전부입니다!
### 서버에서 가져오기(Fetching)
이제 데이터를 소스에 직접 넣는 방식에서 서버에서 동적으로 받아서 처리하는 방식으로 바꿔봅시다. 데이터 prop을 삭제하고 처리할 URL로 변경해 줍시다.
```javascript{3}
// tutorial11.js
React.render(
<CommentBox url="comments.json" />,
document.getElementById('content')
);
```
이 컴포넌트는 이전 것과 다르게, 스스로 다시 렌더링해야 합니다. 컴포넌트는 서버에서 요청이 들어올때까지는 아무 데이터도 가지고 있지 않다가, 특정한 시점에서 새로운 댓글을 렌더할 필요가 있을 것입니다.
### 반응적 state
지금까지, 각각의 컴포넌트는 props를 기반으로 한번 렌더되었습니다. `props`는 불변성을 갖습니다: 그것들은 부모에서 전달되어 부모에게 "소유" 되어 있습니다. 컴포넌트에 상호작용을 구현하기 위해서, 가변성을 갖는 **state**를 소개합니다. `this.state`는 컴포넌트에 한정(private)되며 `this.setState()`를 통해 변경할 수 있습니다. state가 업데이트 되면, 컴포넌트는 자신을 스스로 다시 렌더링합니다.
`render()` 메소드는 `this.props`와 `this.state`를 위한 함수로 선언적으로 작성됩니다. 프레임워크에서 입력값에 따른 UI가 항상 일관성 있음을 보장해줍니다.
서버가 데이터를 가져오면 댓글 데이터가 변경될 것입니다. 댓글 데이터의 배열을 `CommentBox`의 state로 추가해봅시다:
```javascript{3-5,10}
// tutorial12.js
var CommentBox = React.createClass({
getInitialState: function() {
return {data: []};
},
render: function() {
return (
<div className="commentBox">
<h1>댓글</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
});
```
`getInitialState()` 는 컴포넌트의 생명주기동안 한 번만 실행되며 컴포넌트의 초기 state를 설정합니다.
### state 업데이트하기
컴포넌트의 최초 생성 시에, 서버에서 GET 방식으로 JSON을 넘겨받아 최신의 데이터가 state에 반영되길 원했습니다. 실제 애플리케이션에선 이것이 동적인 엔드포인트이지만, 이 예제에서는 정적 JSON 파일을 사용해서 간단하게 만들어보겠습니다.
```javascript
// tutorial13.json
[
{"author": "Pete Hunt", "text": "댓글입니다"},
{"author": "Jordan Walke", "text": "*또 다른* 댓글입니다"}
]
```
서버에 비동기 요청을 위해 jQuery를 사용합니다.
주의: 우리의 앱이 AJAX 애플리케이션으로 변화하고 있기 때문에, 이제 파일 시스템의 파일을 참조하는 대신 웹서버를 사용하도록 앱을 개발해야 합니다. [위에서 언급한 바와 같이](#running-a-server), 우리는 튜토리얼의 나머지 부분에 필요한 기능을 제공하는 서버를 몇 가지 준비해 놓았습니다. [GitHub에 올려놓았으니](https://github.com/reactjs/react-tutorial) 확인해 보세요.
```javascript{6-17}
// tutorial13.js
var CommentBox = React.createClass({
getInitialState: function() {
return {data: []};
},
componentDidMount: 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)
});
},
render: function() {
return (
<div className="commentBox">
<h1>댓글</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
});
```
여기서 `componentDidMount`는 컴포넌트가 렌더링 된 다음 React에 의해 자동으로 호출되는 메소드입니다. 동적 업데이트의 핵심은 `this.setState()`의 호출입니다. 우리가 이전의 댓글 목록을 서버에서 넘어온 새로운 목록으로 변경하면 자동으로 UI가 업데이트 될 것입니다. 이 반응성 덕분에 실시간 업데이트에 아주 작은 수정만 가해집니다. 우리는 여기선 간단한 폴링을 사용할 것이지만 웹소켓등의 다른 기술도 쉽게 사용할 수 있습니다.
```javascript{3,14,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)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>댓글</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
});
React.render(
<CommentBox url="comments.json" pollInterval={2000} />,
document.getElementById('content')
);
```
우리가 여기서 한것은 AJAX 호출을 별도의 메소드로 분리하고 컴포넌트가 처음 로드된 시점부터 2초 간격으로 계속 호출되도록 한 것입니다. 브라우저에서 직접 돌려보고 `comments.json`파일을 수정해보세요; 2초 간격으로 변화되는 모습이 보일 것입니다!
### 새로운 댓글 추가하기
이제 폼을 만들어볼 시간입니다. 우리의 `CommentForm` 컴포넌트는 사용자에게 이름과 내용을 입력받고 댓글을 저장하기 위해 서버에 요청을 전송해야 합니다.
```javascript{5-9}
// tutorial15.js
var CommentForm = React.createClass({
render: function() {
return (
<form className="commentForm">
<input type="text" placeholder="이름" />
<input type="text" placeholder="내용을 입력하세요..." />
<input type="submit" value="올리기" />
</form>
);
}
});
```
이제 폼의 상호작용을 만들어 보겠습니다. 사용자가 폼을 전송하는 시점에 우리는 폼을 초기화하고 서버에 요청을 전송하고 댓글목록을 업데이트해야 합니다. 폼의 submit 이벤트를 감시하고 초기화 해주는 부분부터 시작해 보죠.
```javascript{3-13,16-19}
// tutorial16.js
var CommentForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var author = React.findDOMNode(this.refs.author).value.trim();
var text = React.findDOMNode(this.refs.text).value.trim();
if (!text || !author) {
return;
}
// TODO: 서버에 요청을 전송합니다
React.findDOMNode(this.refs.author).value = '';
React.findDOMNode(this.refs.text).value = '';
return;
},
render: function() {
return (
<form className="commentForm" onSubmit={this.handleSubmit}>
<input type="text" placeholder="이름" ref="author" />
<input type="text" placeholder="내용을 입력하세요..." ref="text" />
<input type="submit" value="올리기" />
</form>
);
}
});
```
##### 이벤트
React는 카멜케이스 네이밍 컨벤션으로 컴포넌트에 이벤트 핸들러를 등록합니다. 폼이 유효한 값으로 submit되었을 때 폼필드들을 초기화하도록 `onSubmit` 핸들러를 등록합니다.
폼 submit에 대한 브라우저의 기본동작을 막기 위해 이벤트시점에 `preventDefault()`를 호출합니다.
##### Refs
우리는 자식 컴포넌트의 이름을 지정하기 위해 `ref` 어트리뷰트를, 컴포넌트를 참조하기 위해 `this.refs`를 사용합니다. 고유한(native) 브라우저 DOM 엘리먼트를 얻기 위해 `React.findDOMNode(component)`를 호출할 수 있습니다.
##### props으로 콜백 처리하기
사용자가 댓글을 등록할 때, 새로운 댓글을 추가하기 위해 댓글목록을 업데이트해주어야 합니다. `CommentBox`가 댓글목록의 state를 소유하고 있기 때문에 이 로직 또한 `CommentBox`에 있는것이 타당합니다.
자식 컴포넌트가 그의 부모에게 데이터를 넘겨줄 필요가 있습니다. 부모의 `render` 메소드에서 새로운 콜백(`handleCommentSubmit`)을 자식에게 넘겨주고, 자식의 `onCommentSubmit` 이벤트에 그것을 바인딩해주는 식으로 구현합니다. 이벤트가 작동될때(triggered)마다, 콜백이 호출됩니다:
```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)
});
},
handleCommentSubmit: function(comment) {
// TODO: 서버에 요청을 수행하고 목록을 업데이트한다
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>댓글</h1>
<CommentList data={this.state.data} />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});
```
사용자가 폼을 전송할 때, `CommentForm`에서 콜백을 호출해 봅시다:
```javascript{10}
// tutorial18.js
var CommentForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var author = React.findDOMNode(this.refs.author).value.trim();
var text = React.findDOMNode(this.refs.text).value.trim();
if (!text || !author) {
return;
}
this.props.onCommentSubmit({author: author, text: text});
React.findDOMNode(this.refs.author).value = '';
React.findDOMNode(this.refs.text).value = '';
return;
},
render: function() {
return (
<form className="commentForm" onSubmit={this.handleSubmit}>
<input type="text" placeholder="이름" ref="author" />
<input type="text" placeholder="이름을 입력하세요..." ref="text" />
<input type="submit" value="올리기" />
</form>
);
}
});
```
이제 콜백이 제자리를 찾았습니다. 우리가 할 일은 서버에 요청을 날리고 목록을 업데이트하는 것 뿐입니다:
```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)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>댓글</h1>
<CommentList data={this.state.data} />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});
```
### 최적화: 낙관적 업데이트
우리의 애플리케이션은 이제 모든 기능을 갖추었습니다. 하지만 댓글이 목록에 업데이트되기 전에 완료요청을 기다리는 게 조금 느린듯한 느낌이 드네요. 우리는 낙관적 업데이트를 통해 댓글이 목록에 추가되도록 함으로써 앱이 좀 더 빨라진 것처럼 느껴지도록 할 수 있습니다.
```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)
});
},
handleCommentSubmit: function(comment) {
var comments = this.state.data;
var newComments = comments.concat([comment]);
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)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>댓글</h1>
<CommentList data={this.state.data} />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});
```
### 축하합니다!
몇 단계를 거쳐 간단하게 댓글창을 만들어 보았습니다. [왜 React인가](/react/docs/why-react-ko-KR.html)에서 더 알아보거나, 혹은 [API 레퍼런스](/react/docs/top-level-api-ko-KR.html)에 뛰어들어 해킹을 시작하세요! 행운을 빕니다!

View File

@@ -40,7 +40,7 @@ For this tutorial, we'll use prebuilt JavaScript files on a CDN. Open up your fa
<title>Hello React</title>
<script src="https://fb.me/react-{{site.react_version}}.js"></script>
<script src="https://fb.me/JSXTransformer-{{site.react_version}}.js"></script>
<script src="https://code.jquery.com/jquery-1.10.0.min.js"></script>
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
</head>
<body>
<div id="content"></div>
@@ -168,7 +168,7 @@ Notice how we're mixing HTML tags and components we've built. HTML components ar
### Using props
Let's create the `Comment` component, which will depend on data passed in from it's parent. Data passed in from a parent component is available as a 'property' on the child component. These 'properties' are accessed through `this.props`. Using props we will be able to read the data passed to the `Comment` from the `CommentList`, and render some markup:
Let's create the `Comment` component, which will depend on data passed in from its parent. Data passed in from a parent component is available as a 'property' on the child component. These 'properties' are accessed through `this.props`. Using props we will be able to read the data passed to the `Comment` from the `CommentList`, and render some markup:
```javascript
// tutorial4.js
@@ -212,7 +212,7 @@ Note that we have passed some data from the parent `CommentList` component to th
Markdown is a simple way to format your text inline. For example, surrounding text with asterisks will make it emphasized.
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):
First, add the third-party library **marked** 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{7}
<!-- index.html -->
@@ -221,15 +221,14 @@ First, add the third-party **Showdown** library to your application. This is a J
<script src="https://fb.me/react-{{site.react_version}}.js"></script>
<script src="https://fb.me/JSXTransformer-{{site.react_version}}.js"></script>
<script src="https://code.jquery.com/jquery-1.10.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>
</head>
```
Next, let's convert the comment text to Markdown and output it:
```javascript{2,10}
```javascript{9}
// tutorial6.js
var converter = new Showdown.converter();
var Comment = React.createClass({
render: function() {
return (
@@ -237,25 +236,24 @@ var Comment = React.createClass({
<h2 className="commentAuthor">
{this.props.author}
</h2>
{converter.makeHtml(this.props.children.toString())}
{marked(this.props.children.toString())}
</div>
);
}
});
```
All we're doing here is calling the Showdown library. We need to convert `this.props.children` from React's wrapped text to a raw string that Showdown will understand so we explicitly call `toString()`.
All we're doing here is calling the marked library. We need to convert `this.props.children` from React's wrapped text to a raw string that marked will understand so we explicitly call `toString()`.
But there's a problem! Our rendered comments look like this in the browser: "`<p>`This is `<em>`another`</em>` comment`</p>`". We want those tags to actually render as HTML.
That's React protecting you from an XSS attack. There's a way to get around it but the framework warns you not to use it:
```javascript{5,11}
```javascript{4,10}
// tutorial7.js
var converter = new Showdown.converter();
var Comment = React.createClass({
render: function() {
var rawMarkup = converter.makeHtml(this.props.children.toString());
var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
return (
<div className="comment">
<h2 className="commentAuthor">
@@ -268,9 +266,9 @@ var Comment = React.createClass({
});
```
This is a special API that intentionally makes it difficult to insert raw HTML, but for Showdown we'll take advantage of this backdoor.
This is a special API that intentionally makes it difficult to insert raw HTML, but for marked we'll take advantage of this backdoor.
**Remember:** by using this feature you're relying on Showdown to be secure.
**Remember:** by using this feature you're relying on marked to be secure. In this case, we pass `sanitize: true` which tells marked to escape any HTML markup in the source instead of passing it through unchanged.
### Hook up the data model

174
docs/docs/videos.ko-KR.md Normal file
View File

@@ -0,0 +1,174 @@
---
id: videos-ko-KR
title: 비디오들
permalink: videos-ko-KR.html
prev: conferences-ko-KR.html
next: complementary-tools-ko-KR.html
---
### Rethinking best practices - JSConf.eu
<iframe width="650" height="366" src="https://www.youtube.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe>
"페이스북과 인스타그램에서, 우리는 React 를 이용해 웹에서 벌어질 수 있는 한계를 뛰어넘으려 노력하고 있습니다. 저는 프레임워크에 대한 짤막한 소개로 시작해서, 논쟁이 벌어질 수 있는 다음의 세가지 주제로 넘어갈겁니다. 템플릿의 개념을 버리고 Javascript 를 이용해 View 를 구축하기, 자료가 변할때 전체 어플리케이션을 다시 그리기(“re-rendering”), 그리고 DOM과 events의 경량화된 구현 입니다." -- [Pete Hunt](http://www.petehunt.net/)
* * *
### Thinking in react - tagtree.tv
[tagtree.tv](http://tagtree.tv/)의 비디오는 간단한 어플리케이션을 구성하면서 [Thinking in React](/react/docs/thinking-in-react-ko-KR.html)의 원리들을 전달합니다.
<figure>[![](/react/img/docs/thinking-in-react-tagtree.png)](http://tagtree.tv/thinking-in-react)</figure>
* * *
### Secrets of the Virtual DOM - MtnWest JS
<iframe width="650" height="366" src="https://www.youtube.com/embed/h3KksH8gfcQ" frameborder="0" allowfullscreen></iframe>
"이번에는 왜 우리가 virtual DOM을 만들었는지, 이것이 다른 시스템들과는 어떻게 다른지, 그리고 브라우져 기술들의 미래와 어떻게 관련이 있는지에 대해서 이야기 해 볼 겁니다." -- [Pete Hunt](http://www.petehunt.net/)
* * *
### Going big with React
"이 발표에서, 이 모든 JS 프레임워크가 다음을 약속하는것처럼 보입니다: 꺠끗한 구현들, 빠른 코드 디자인, 완전한 수행. 그런데 당신이 Javascript 스트레스 테스트를 할때, 어떤 일이 발생합니까? 혹은 6MB의 코드를 던지면 무슨일이 발생합니까? 이번에는 높은 스트레스 환경에서 React가 어떻게 작동하는지, 그리고 이것이 우리 팀이 방대한 크기의 코드를 안전하게 구성하는데 어떻게 도움이 되어줄지를 조사해 볼겁니다."
[![](https://i.vimeocdn.com/video/481670116_650.jpg)](https://skillsmatter.com/skillscasts/5429-going-big-with-react#video)
* * *
### CodeWinds
CodeWinds Episode 4 에서 [Pete Hunt](http://www.petehunt.net/)와 [Jeff Barczewski](http://jeff.barczewski.com/)가 React에 대해서 이야기 합니다.
<figure>[![](/react/img/docs/codewinds-004.png)](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>
[방송 자료 읽어보기](http://codewinds.com/4)
* * *
### JavaScript Jabber
Javascript Jabber 73에서 [Pete Hunt](http://www.petehunt.net/)와 [Jordan Walke](https://github.com/jordwalke)가 React에 대해서 이야기했습니다.
<figure>[![](/react/img/docs/javascript-jabber.png)](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>
[전체 기록 읽어보기](http://javascriptjabber.com/073-jsj-react-with-pete-hunt-and-jordan-walke/)
* * *
### Introduction to React.js - Facebook Seattle
<iframe width="650" height="366" src="https://www.youtube.com/embed/XxVg_s8xAms" frameborder="0" allowfullscreen></iframe>
By [Tom Occhino](http://tomocchino.com/), [Jordan Walke](https://github.com/jordwalke)
* * *
### Backbone + React + Middleman Screencast
<iframe width="650" height="488" src="https://www.youtube.com/embed/iul1fWHVU6A" frameborder="0" allowfullscreen></iframe>
Backbone은 React로 REST API를 제공하기 위한 아주 좋은 방법입니다. 이 화면중개는 [Backbone-React-Component](https://github.com/magalhas/backbone-react-component)을 이용해서 어떻게 이 두가지를 병합하는지 보여줍니다. Middleman은 이 예제에서 사용되는 프레임워크이지만, 쉽게 다른 프레임워크로 대체하실 수 있습니다. 지원되는 템플릿은 [이곳](https://github.com/jbhatab/middleman-backbone-react-template)에서 찾으실 수 있습니다. -- [열린 마음의 혁명들](http://www.openmindedinnovations.com/)
* * *
### Developing User Interfaces With React - Super VanJS
<iframe width="650" height="366" src="https://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="366" src="https://www.youtube.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe>
by [Stoyan Stefanov](http://www.phpied.com/)
* * *
### React, or how to make life simpler - FrontEnd Dev Conf '14
<iframe width="560" height="366" src="https://www.youtube.com/embed/YJNUK0EA_Jo" frameborder="0" allowfullscreen></iframe>
**러시아어** by [Alexander Solovyov](http://solovyov.net/)
* * *
### "Functional DOM programming" - Meteor DevShop 11
<iframe width="650" height="366" src="https://www.youtube.com/embed/qqVbr_LaCIo" frameborder="0" allowfullscreen></iframe>
* * *
### "Rethinking Web App Development at Facebook" - Facebook F8 Conference 2014
<iframe width="650" height="366" src="https://www.youtube.com/embed/nYkdrAPrdcw" frameborder="0" allowfullscreen></iframe>
* * *
### React and Flux: Building Applications with a Unidirectional Data Flow - Forward JS 2014
<iframe width="650" height="366" src="https://www.youtube.com/embed/i__969noyAM" frameborder="0" allowfullscreen></iframe>
Facebook 개발자 [Bill Fisher](http://twitter.com/fisherwebdev)와 [Jing Chen](http://twitter.com/jingc)가 Flux 와 React 에 대해서 이야기합니다. 그리고 어떻게 단일 방향의 자료흐름을 사용하는 어플리케이션 구조가 방대한 코드를 정리하는지에 대해서 이야기합니다."
* * *
### Server-Side Rendering of Isomorphic Apps at SoundCloud
<iframe src="https://player.vimeo.com/video/108488724" width="650" height="365" frameborder="0" allowfullscreen></iframe>
Server-side rendering을 위해 [SoundCloud](https://developers.soundcloud.com/blog/)가 React 와 Flux를 사용하는지 by [Andres Suarez](https://github.com/zertosh)
[발표 자료와 예제 코드](https://github.com/zertosh/ssr-demo-kit)
* * *
### Introducing React Native (+Playlist) - React.js Conf 2015
<iframe width="650" height="366" src="https://www.youtube.com/watch?v=KVZ-P-ZI6W4&index=1&list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
2015년에 [Tom Occhino](https://twitter.com/tomocchino)님이 React의 과거와 현재를 리뷰하고 나아갈 방향을 제시했습니다.

View File

@@ -8,29 +8,33 @@ next: complementary-tools.html
### Rethinking best practices - JSConf.eu
<iframe width="650" height="315" src="//www.youtube.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="366" src="https://www.youtube.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe>
"At Facebook and Instagram, were trying to push the limits of whats 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>[![](/react/img/docs/thinking-in-react-tagtree.png)](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>
<iframe width="650" height="366" src="https://www.youtube.com/embed/h3KksH8gfcQ" frameborder="0" allowfullscreen></iframe>
"In this talk Ill 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/)
* * *
### Going big with React ###
"On paper, all those JS frameworks look promising: clean implementations, quick code design, flawless execution. But what happens when you stress test Javascript? What happens when you throw 6 megabytes of code at it? In this talk, we'll investigate how React performs in a high stress situation, and how it has helped our team build safe code on a massive scale."
<figure>[![](https://i.vimeocdn.com/video/481670116_650.jpg)](https://skillsmatter.com/skillscasts/5429-going-big-with-react#video)</figure>
* * *
### CodeWinds
@@ -63,6 +67,7 @@ A [tagtree.tv](http://tagtree.tv/) video conveying the principles of [Thinking i
[Read the episode notes](http://codewinds.com/4)
* * *
### JavaScript Jabber
@@ -90,59 +95,79 @@ A [tagtree.tv](http://tagtree.tv/) video conveying the principles of [Thinking i
[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>
<iframe width="650" height="366" src="https://www.youtube.com/embed/XxVg_s8xAms" frameborder="0" allowfullscreen></iframe>
By [Tom Occhino](http://tomocchino.com/) and [Jordan Walke](https://github.com/jordwalke)
* * *
### Backbone + React + Middleman Screencast
<iframe width="650" height="315" src="//www.youtube.com/embed/iul1fWHVU6A" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="488" src="https://www.youtube.com/embed/iul1fWHVU6A" frameborder="0" allowfullscreen></iframe>
Backbone is a great way in interface a REST API with React. This screencast shows how to integate the two using [Backbone-React-Component](https://github.com/magalhas/backbone-react-component). Middleman is the framework used in this example but could easily be replaced with other frameworks. A supported template of this can be found [here](https://github.com/jbhatab/middleman-backbone-react-template). -- [Open Minded Innovations](http://www.openmindedinnovations.com/)
* * *
### Developing User Interfaces With React - Super VanJS
<iframe width="650" height="315" src="//www.youtube.com/embed/1OeXsL5mr4g" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="366" src="https://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>
<iframe width="650" height="366" src="https://www.youtube.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe>
by [Stoyan Stefanov](http://www.phpied.com/)
* * *
### React, or how to make life simpler - FrontEnd Dev Conf '14
<iframe width="560" height="315" src="//www.youtube.com/embed/YJNUK0EA_Jo" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="366" src="https://www.youtube.com/embed/YJNUK0EA_Jo" 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>
<iframe width="650" height="366" src="https://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>
<iframe width="650" height="366" src="https://www.youtube.com/embed/nYkdrAPrdcw" frameborder="0" allowfullscreen></iframe>
* * *
### React and Flux: Building Applications with a Unidirectional Data Flow - Forward JS 2014
<iframe width="650" height="315" src="//www.youtube.com/embed/i__969noyAM" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="366" src="https://www.youtube.com/embed/i__969noyAM" frameborder="0" allowfullscreen></iframe>
Facebook engineers [Bill Fisher](http://twitter.com/fisherwebdev) and [Jing Chen](http://twitter.com/jingc) talk about Flux and React, and how using an application architecture with a unidirectional data flow cleans up a lot of their code.
* * *
### Server-Side Rendering of Isomorphic Apps at SoundCloud
<iframe src="//player.vimeo.com/video/108488724" width="500" height="281" frameborder="0" allowfullscreen></iframe>
<iframe src="https://player.vimeo.com/video/108488724" width="650" height="365" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
Walk-through by [Andres Suarez](https://github.com/zertosh) on how [SoundCloud](https://developers.soundcloud.com/blog/) is using React and Flux for server-side rendering.
[Slides and sample code](https://github.com/zertosh/ssr-demo-kit)
* * *
### Introducing React Native (+Playlist) - React.js Conf 2015
<iframe width="650" height="315" src="//www.youtube.com/watch?v=KVZ-P-ZI6W4&index=1&list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="366" src="https://www.youtube.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
[Tom Occhino](https://twitter.com/tomocchino) reviews the past and present of React in 2015, and teases where it's going next.

Binary file not shown.

Binary file not shown.

View File

@@ -6,6 +6,6 @@ id: html-jsx
<div class="jsxCompiler">
<h1>HTML to JSX Compiler</h1>
<div id="jsxCompiler"></div>
<script src="http://reactjs.github.io/react-magic/htmltojsx.min.js"></script>
<script src="https://reactjs.github.io/react-magic/htmltojsx.min.js"></script>
<script src="js/html-jsx.js"></script>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Some files were not shown because too many files have changed in this diff Show More