├── .eslintrc ├── .gitignore ├── README.md ├── assets ├── animate │ └── index.css ├── load-on-demand │ ├── async.css │ └── index.css ├── react-router-slide │ └── index.less └── react-router │ └── index.css ├── examples ├── ReactNativeART │ ├── .babelrc │ ├── README.md │ ├── Rectangle.js │ ├── android │ │ ├── .gradle │ │ │ └── 2.4 │ │ │ │ └── taskArtifacts │ │ │ │ ├── cache.properties │ │ │ │ ├── cache.properties.lock │ │ │ │ ├── fileHashes.bin │ │ │ │ ├── fileSnapshots.bin │ │ │ │ ├── outputFileStates.bin │ │ │ │ └── taskArtifacts.bin │ │ ├── app │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── reactnativeart │ │ │ │ │ └── MainActivity.java │ │ │ │ └── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ └── values │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ ├── build.gradle │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── settings.gradle │ ├── index.android.js │ ├── index.ios.js │ ├── ios │ │ ├── ReactNativeART.xcodeproj │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcuserdata │ │ │ │ │ └── yiminghe.xcuserdatad │ │ │ │ │ └── UserInterfaceState.xcuserstate │ │ │ ├── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ │ └── ReactNativeART.xcscheme │ │ │ └── xcuserdata │ │ │ │ └── yiminghe.xcuserdatad │ │ │ │ └── xcschemes │ │ │ │ └── xcschememanagement.plist │ │ ├── ReactNativeART │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Base.lproj │ │ │ │ └── LaunchScreen.xib │ │ │ ├── Images.xcassets │ │ │ │ └── AppIcon.appiconset │ │ │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ └── main.m │ │ ├── ReactNativeARTTests │ │ │ ├── Info.plist │ │ │ └── ReactNativeARTTests.m │ │ └── main.jsbundle │ └── package.json ├── animate.html ├── animate.js ├── code-share │ ├── Component.jsx │ ├── Page.jsx │ ├── demo.html │ ├── index.js │ ├── server.js │ └── serverRender.jsx ├── diff-children.html ├── diff-children.js ├── flux.html ├── flux.js ├── key-lifecycle.html ├── key-lifecycle.js ├── load-on-demand.html ├── load-on-demand.js ├── react-art.html ├── react-art.js ├── react-intl.html ├── react-intl.js ├── react-router-slide.html ├── react-router-slide.js ├── react-router.html ├── react-router.js ├── svg.html ├── svg.js ├── tb-app.html └── tb-app.js ├── package.json ├── reference.md ├── scripts └── pre-gh-pages.sh ├── src ├── animate │ └── index.js ├── flux │ ├── App.js │ ├── AppDispatcher.js │ ├── User.js │ ├── UserAction.js │ ├── UserStore.js │ └── index.js ├── key-lifecycle │ ├── Component.js │ └── index.js ├── load-on-demand │ ├── async.js │ └── index.js ├── react-art │ ├── README.md │ └── index.js ├── react-router │ ├── App.js │ ├── IndexPage.js │ ├── Main.js │ ├── State.js │ ├── index.js │ └── util.js ├── svg │ ├── ClipPath.js │ ├── Line.js │ ├── StrikeDash.js │ └── index.js └── tb-app │ ├── App.js │ ├── List.js │ ├── Search.js │ ├── data.json │ └── index.js ├── tests ├── index.js └── react-router │ └── test.spec.js └── tutorial ├── common └── lifecycle.svg ├── en-us ├── component │ └── how-to-write-a-react-component.md ├── env │ ├── es6-in-harmony.md │ ├── modulex-browserify-npm.md │ └── setup-your-playground.md ├── index.md └── internal │ ├── object-model.md │ ├── object-model.png │ └── object-model.sketch └── zh-cn ├── advanced.html ├── component ├── code-style │ ├── comment.md │ ├── css.md │ └── js.md ├── component-code-style.md ├── component-design.md ├── how-to-write-a-react-component.md └── kissy-react-compare.md ├── env ├── modulex-browserify-npm.md ├── setup-project-env.md └── setup-your-playground.md ├── intro.html ├── meetings └── react-europe-2015.html └── practice ├── checkbox.md └── tb-app.md /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-airbnb", 3 | "parser": "babel-eslint", 4 | "rules": { 5 | "react/prefer-es6-class": [ 6 | 0 7 | ], 8 | "no-var": [ 9 | 0 10 | ], 11 | "no-console": [ 12 | 0 13 | ], 14 | "func-names": [ 15 | 0 16 | ], 17 | "space-before-function-paren": [ 18 | 0 19 | ], 20 | "no-param-reassign": [ 21 | 0 22 | ], 23 | "vars-on-top": [ 24 | 0 25 | ], 26 | "react/no-multi-comp": [0] 27 | }, 28 | "env": { 29 | "node": true, 30 | "mocha": true 31 | } 32 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components/ 2 | config.js 3 | mx_modules/ 4 | nohup.out 5 | *.iml 6 | *.cfg 7 | .idea/ 8 | .ipr 9 | .iws 10 | *~ 11 | ~* 12 | *.diff 13 | *.log 14 | *.patch 15 | *.bak 16 | .DS_Store 17 | Thumbs.db 18 | .project 19 | .*proj 20 | .svn/ 21 | *.swp 22 | out/ 23 | node_modules/ 24 | build/ 25 | dist/ 26 | coverage 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # learning-react 2 | 3 | materials about learning react 4 | 5 | ## Development 6 | 7 | ``` 8 | npm install 9 | npm start 10 | ``` 11 | 12 | ## Example 13 | 14 | http://localhost:9000/examples/ 15 | 16 | online example: http://yiminghe.github.io/learning-react/examples/ 17 | 18 | ## Test Case 19 | 20 | ``` 21 | npm run chrome-test 22 | npm test 23 | ``` 24 | 25 | ## Coverage 26 | 27 | ``` 28 | npm run coverage 29 | ``` 30 | 31 | ## Tutorials 32 | 33 | https://github.com/yiminghe/learning-react/blob/master/tutorial/en-us/index.md 34 | 35 | ### online 36 | 37 | [react 入门](http://yiminghe.github.io/learning-react/tutorial/zh-cn/intro.html) 38 | 39 | [react 进阶](http://yiminghe.github.io/learning-react/tutorial/zh-cn/advanced.html) 40 | 41 | ## Reference 42 | 43 | https://github.com/yiminghe/learning-react/blob/master/reference.md 44 | 45 | ## Our components based on React 46 | 47 | [https://github.com/react-component](https://github.com/react-component) 48 | 49 | ## License 50 | 51 | Sample codes and articles are released under the MIT license. 52 | -------------------------------------------------------------------------------- /assets/animate/index.css: -------------------------------------------------------------------------------- 1 | .example-enter { 2 | opacity: 0.01; 3 | transition: opacity 1s ease-in; 4 | } 5 | .example-enter.example-enter-active { 6 | opacity: 1; 7 | } 8 | .example-leave { 9 | opacity: 1; 10 | transition: opacity 1s ease-in; 11 | } 12 | .example-leave.example-leave-active { 13 | opacity: 0.01; 14 | } -------------------------------------------------------------------------------- /assets/load-on-demand/async.css: -------------------------------------------------------------------------------- 1 | .my-content { 2 | color:red; 3 | } -------------------------------------------------------------------------------- /assets/load-on-demand/index.css: -------------------------------------------------------------------------------- 1 | .my-button { 2 | color: gray; 3 | } -------------------------------------------------------------------------------- /assets/react-router-slide/index.less: -------------------------------------------------------------------------------- 1 | @easing-in-out: cubic-bezier(0.35, 0, 0.25, 1); 2 | 3 | @effect-duration: .3s; 4 | 5 | .rr { 6 | &-slide-horizontal-backward-enter { 7 | transform: translateX(-100%); 8 | } 9 | 10 | &-slide-horizontal-backward-enter&-slide-horizontal-backward-enter-active { 11 | transform: translateX(0); 12 | transition: transform @effect-duration @easing-in-out; 13 | } 14 | 15 | &-slide-horizontal-backward-leave { 16 | position: absolute; 17 | top: 0; 18 | left: 0; 19 | right: 0; 20 | bottom: 0; 21 | transform: translateX(0); 22 | } 23 | 24 | &-slide-horizontal-backward-leave&-slide-horizontal-backward-leave-active { 25 | transform: translateX(100%); 26 | transition: transform @effect-duration @easing-in-out; 27 | } 28 | 29 | &-slide-horizontal-forward-enter { 30 | transform: translateX(100%); 31 | } 32 | 33 | &-slide-horizontal-forward-enter&-slide-horizontal-forward-enter-active { 34 | transform: translateX(0); 35 | transition: transform @effect-duration @easing-in-out; 36 | } 37 | 38 | &-slide-horizontal-forward-leave { 39 | position: absolute; 40 | transform: translateX(0); 41 | top: 0; 42 | right: 0; 43 | left: 0; 44 | bottom: 0; 45 | } 46 | 47 | &-slide-horizontal-forward-leave&-slide-horizontal-forward-leave-active { 48 | transform: translateX(-100%); 49 | transition: transform @effect-duration @easing-in-out; 50 | } 51 | } -------------------------------------------------------------------------------- /assets/react-router/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Helvetica Neue", Arial; 3 | font-weight: 200; 4 | } 5 | 6 | a { 7 | color: hsl(200, 50%, 50%); 8 | } 9 | 10 | a.active { 11 | color: hsl(20, 50%, 50%); 12 | } 13 | 14 | #example { 15 | position: absolute; 16 | } 17 | 18 | .App { 19 | width: 1000px; 20 | margin:0 auto; 21 | } 22 | 23 | .Master { 24 | overflow: auto; 25 | padding: 10px 40px; 26 | border-right: 1px solid #ccc; 27 | text-align: center; 28 | } 29 | 30 | .Detail { 31 | overflow: auto; 32 | padding: 40px; 33 | } -------------------------------------------------------------------------------- /examples/ReactNativeART/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "whitelist":["es6.constants"] 3 | } -------------------------------------------------------------------------------- /examples/ReactNativeART/README.md: -------------------------------------------------------------------------------- 1 | ## ReactNativeART test 2 | 3 | web version: https://github.com/yiminghe/learning-react/tree/master/src/react-art 4 | 5 | android not supported because of missing ReactNativeArt ... 6 | 7 | ### install 8 | 9 | ``` 10 | npm install 11 | ``` 12 | 13 | link ART in react-native/libraries/ART: http://facebook.github.io/react-native/docs/linking-libraries-ios.html#content 14 | 15 | ### run 16 | 17 | open `ios/ReactNativeART.xcodeproj` in Xcode and run 18 | 19 | 20 | ### demo 21 | 22 | ![img](http://gtms02.alicdn.com/tps/i2/TB1wsGUJFXXXXa8XFXXygnAGFXX-730-1015.png) 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/ReactNativeART/Rectangle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013-2014 Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | * @providesModule Rectangle.art 10 | * @typechecks 11 | * 12 | * Example usage: 13 | * 19 | * 20 | * Additional optional properties: 21 | * (Number) radius 22 | * (Number) radiusTopLeft 23 | * (Number) radiusTopRight 24 | * (Number) radiusBottomLeft 25 | * (Number) radiusBottomRight 26 | * 27 | */ 28 | 29 | var React = require('react-native'); 30 | var ReactART = require('ReactNativeART'); 31 | 32 | // var Group = ReactART.Group; 33 | // var Shape = ReactART.Shape; 34 | // var Surface = ReactART.Surface; 35 | // var Transform = ReactART.Transform; 36 | 37 | var Props = React.PropTypes; 38 | var Shape = ReactART.Shape; 39 | var getPath = ReactART.Path; 40 | 41 | /** 42 | * Rectangle is a React component for drawing rectangles. Like other ReactART 43 | * components, it must be used in a . 44 | */ 45 | var Rectangle = React.createClass({ 46 | propTypes: { 47 | width: Props.number.isRequired, 48 | height: Props.number.isRequired, 49 | radius: Props.number, 50 | radiusTopLeft: Props.number, 51 | radiusTopRight: Props.number, 52 | radiusBottomRight: Props.number, 53 | radiusBottomLeft: Props.number, 54 | }, 55 | 56 | render() { 57 | var width = this.props.width; 58 | var height = this.props.height; 59 | var radius = this.props.radius ? this.props.radius : 0; 60 | 61 | // if unspecified, radius(Top|Bottom)(Left|Right) defaults to the radius 62 | // property 63 | var tl = this.props.radiusTopLeft ? this.props.radiusTopLeft : radius; 64 | var tr = this.props.radiusTopRight ? this.props.radiusTopRight : radius; 65 | var br = this.props.radiusBottomRight ? 66 | this.props.radiusBottomRight : radius; 67 | var bl = this.props.radiusBottomLeft ? this.props.radiusBottomLeft : radius; 68 | 69 | var path = getPath(); 70 | 71 | // for negative width/height, offset the rectangle in the negative x/y 72 | // direction. for negative radius, just default to 0. 73 | if (width < 0) { 74 | path.move(width, 0); 75 | width = -width; 76 | } 77 | if (height < 0) { 78 | path.move(0, height); 79 | height = -height; 80 | } 81 | if (tl < 0) { tl = 0; } 82 | if (tr < 0) { tr = 0; } 83 | if (br < 0) { br = 0; } 84 | if (bl < 0) { bl = 0; } 85 | 86 | // disable border radius if it doesn't fit within the specified 87 | // width/height 88 | if (tl + tr > width) { tl = 0; tr = 0; } 89 | if (bl + br > width) { bl = 0; br = 0; } 90 | if (tl + bl > height) { tl = 0; bl = 0; } 91 | if (tr + br > height) { tr = 0; br = 0; } 92 | 93 | path.move(0, tl); 94 | 95 | if (tl > 0) { path.arc(tl, -tl); } 96 | path.line(width - (tr + tl), 0); 97 | 98 | if (tr > 0) { path.arc(tr, tr); } 99 | path.line(0, height - (tr + br)); 100 | 101 | if (br > 0) { path.arc(-br, br); } 102 | path.line(- width + (br + bl), 0); 103 | 104 | if (bl > 0) { path.arc(-bl, -bl); } 105 | path.line(0, - height + (bl + tl)); 106 | 107 | return ; 108 | }, 109 | }); 110 | 111 | module.exports = Rectangle; 112 | -------------------------------------------------------------------------------- /examples/ReactNativeART/android/.gradle/2.4/taskArtifacts/cache.properties: -------------------------------------------------------------------------------- 1 | #Tue Sep 22 20:18:49 CST 2015 2 | -------------------------------------------------------------------------------- /examples/ReactNativeART/android/.gradle/2.4/taskArtifacts/cache.properties.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/examples/ReactNativeART/android/.gradle/2.4/taskArtifacts/cache.properties.lock -------------------------------------------------------------------------------- /examples/ReactNativeART/android/.gradle/2.4/taskArtifacts/fileHashes.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/examples/ReactNativeART/android/.gradle/2.4/taskArtifacts/fileHashes.bin -------------------------------------------------------------------------------- /examples/ReactNativeART/android/.gradle/2.4/taskArtifacts/fileSnapshots.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/examples/ReactNativeART/android/.gradle/2.4/taskArtifacts/fileSnapshots.bin -------------------------------------------------------------------------------- /examples/ReactNativeART/android/.gradle/2.4/taskArtifacts/outputFileStates.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/examples/ReactNativeART/android/.gradle/2.4/taskArtifacts/outputFileStates.bin -------------------------------------------------------------------------------- /examples/ReactNativeART/android/.gradle/2.4/taskArtifacts/taskArtifacts.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/examples/ReactNativeART/android/.gradle/2.4/taskArtifacts/taskArtifacts.bin -------------------------------------------------------------------------------- /examples/ReactNativeART/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.reactnativeart" 9 | minSdkVersion 16 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | ndk { 14 | abiFilters "armeabi-v7a", "x86" 15 | } 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | compile fileTree(dir: 'libs', include: ['*.jar']) 27 | compile 'com.android.support:appcompat-v7:23.0.0' 28 | compile 'com.facebook.react:react-native:0.11.+' 29 | } 30 | -------------------------------------------------------------------------------- /examples/ReactNativeART/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /examples/ReactNativeART/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/ReactNativeART/android/app/src/main/java/com/reactnativeart/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.reactnativeart; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.KeyEvent; 6 | 7 | import com.facebook.react.LifecycleState; 8 | import com.facebook.react.ReactInstanceManager; 9 | import com.facebook.react.ReactRootView; 10 | import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; 11 | import com.facebook.react.shell.MainReactPackage; 12 | import com.facebook.soloader.SoLoader; 13 | 14 | public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { 15 | 16 | private ReactInstanceManager mReactInstanceManager; 17 | private ReactRootView mReactRootView; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | mReactRootView = new ReactRootView(this); 23 | 24 | mReactInstanceManager = ReactInstanceManager.builder() 25 | .setApplication(getApplication()) 26 | .setBundleAssetName("index.android.bundle") 27 | .setJSMainModuleName("index.android") 28 | .addPackage(new MainReactPackage()) 29 | .setUseDeveloperSupport(BuildConfig.DEBUG) 30 | .setInitialLifecycleState(LifecycleState.RESUMED) 31 | .build(); 32 | 33 | mReactRootView.startReactApplication(mReactInstanceManager, "ReactNativeART", null); 34 | 35 | setContentView(mReactRootView); 36 | } 37 | 38 | @Override 39 | public boolean onKeyUp(int keyCode, KeyEvent event) { 40 | if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { 41 | mReactInstanceManager.showDevOptionsDialog(); 42 | return true; 43 | } 44 | return super.onKeyUp(keyCode, event); 45 | } 46 | 47 | @Override 48 | public void invokeDefaultOnBackPressed() { 49 | super.onBackPressed(); 50 | } 51 | 52 | @Override 53 | protected void onPause() { 54 | super.onPause(); 55 | 56 | if (mReactInstanceManager != null) { 57 | mReactInstanceManager.onPause(); 58 | } 59 | } 60 | 61 | @Override 62 | protected void onResume() { 63 | super.onResume(); 64 | 65 | if (mReactInstanceManager != null) { 66 | mReactInstanceManager.onResume(this); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /examples/ReactNativeART/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/examples/ReactNativeART/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/ReactNativeART/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/examples/ReactNativeART/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/ReactNativeART/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/examples/ReactNativeART/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/ReactNativeART/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/examples/ReactNativeART/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/ReactNativeART/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ReactNativeART 3 | 4 | -------------------------------------------------------------------------------- /examples/ReactNativeART/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/ReactNativeART/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/ReactNativeART/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /examples/ReactNativeART/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/examples/ReactNativeART/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /examples/ReactNativeART/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=http\://localhost:8080/gradle-2.4-all.zip 6 | -------------------------------------------------------------------------------- /examples/ReactNativeART/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /examples/ReactNativeART/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /examples/ReactNativeART/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'ReactNativeART' 2 | 3 | include ':app' 4 | -------------------------------------------------------------------------------- /examples/ReactNativeART/index.android.js: -------------------------------------------------------------------------------- 1 | require('./index.ios'); 2 | -------------------------------------------------------------------------------- /examples/ReactNativeART/index.ios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | var Dimensions = require('Dimensions'); 11 | var windowWidth = Dimensions.get('window').width; 12 | var windowHeight = Dimensions.get('window').height; 13 | 14 | /* eslint react/no-multi-comp:0 */ 15 | var React = require('react-native'); 16 | var ReactART = require('ReactNativeART'); 17 | var { 18 | // NavigatorIOS, 19 | AppRegistry, 20 | PropTypes, 21 | // StyleSheet, 22 | // Text, 23 | View, 24 | } = React; 25 | 26 | var Group = ReactART.Group; 27 | var Shape = ReactART.Shape; 28 | var Surface = ReactART.Surface; 29 | // var Transform = ReactART.Transform; 30 | var ARTText = ReactART.Text; 31 | var Rectangle = require('./Rectangle'); 32 | 33 | const d3 = require('d3'); 34 | const monthText = ['', 'Jan', 'Feb', 'Mar', 'Apr', 35 | 'May', 'Jun', 'Jul', 'Aug', 'Sep', 36 | 'Oct', 'Nov', 'Dec']; 37 | 38 | 39 | class Bar extends React.Component { 40 | constructor(props) { 41 | // for label right and bottom 42 | super(props); 43 | this.gap = 20; 44 | this.monthScale = d3.scale.linear().domain([0, 12]).range([0, props.width - this.gap]); 45 | this.valueScale = d3.scale.linear().domain([0, 10]).range([{ 46 | color: '#add8e6', 47 | height: 0, 48 | }, { 49 | color: '#4169e1', 50 | height: props.height - this.gap, 51 | }]); 52 | this.rectangleWidth = (props.width - this.gap) / 24; 53 | } 54 | 55 | getRects() { 56 | return this.props.data.map((d) => { 57 | const value = this.valueScale(d.value); 58 | const height = value.height; 59 | const y = this.props.height - height - this.gap; 60 | const x = this.monthScale(d.month) - this.rectangleWidth * 1.5; 61 | return (); 69 | }); 70 | } 71 | 72 | getXAxis() { 73 | const months = []; 74 | var height = this.props.height - this.gap; 75 | for (let i = 1; i <= 12; i++) { 76 | const value = this.monthScale(i) - this.rectangleWidth * 2; 77 | months.push(( 81 | 85 | {monthText[i]} 86 | 87 | )); 88 | } 89 | var width = this.props.width - this.gap; 90 | return ( 91 | 96 | {months} 97 | ); 98 | } 99 | 100 | getYAxis() { 101 | const values = []; 102 | var gap = this.gap; 103 | var yHeight = this.props.height - this.gap; 104 | for (let i = 1; i <= 10; i++) { 105 | const value = this.valueScale(i); 106 | const height = value.height; 107 | const y = yHeight - height; 108 | values.push( 109 | {i} 110 | 111 | ); 112 | } 113 | return ( 114 | 115 | {values} 116 | ); 117 | } 118 | 119 | render() { 120 | return ( 121 | {this.getYAxis()} 122 | {this.getXAxis()} 123 | 124 | {this.getRects()} 125 | 126 | ); 127 | } 128 | } 129 | 130 | Bar.propTypes = { 131 | width: PropTypes.number, 132 | height: PropTypes.number, 133 | data: PropTypes.object, 134 | }; 135 | 136 | const data = []; 137 | 138 | for (let i = 1; i < 13; i++) { 139 | data.push({ 140 | month: i, 141 | value: Math.floor(Math.random() * 10) + 1, 142 | }); 143 | } 144 | 145 | /* 146 | class ReactNativeART extends React.Component { 147 | render() { 148 | return ( 149 | 155 | ); 156 | } 157 | } 158 | */ 159 | 160 | class ReactNativeART2 extends React.Component { 161 | render() { 162 | return ( 163 | 164 | 165 | 166 | ); 167 | } 168 | } 169 | 170 | AppRegistry.registerComponent('ReactNativeART', () => ReactNativeART2); 171 | -------------------------------------------------------------------------------- /examples/ReactNativeART/ios/ReactNativeART.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/ReactNativeART/ios/ReactNativeART.xcodeproj/project.xcworkspace/xcuserdata/yiminghe.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/examples/ReactNativeART/ios/ReactNativeART.xcodeproj/project.xcworkspace/xcuserdata/yiminghe.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /examples/ReactNativeART/ios/ReactNativeART.xcodeproj/xcshareddata/xcschemes/ReactNativeART.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /examples/ReactNativeART/ios/ReactNativeART.xcodeproj/xcuserdata/yiminghe.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ReactNativeART.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 00E356ED1AD99517003FC87E 16 | 17 | primary 18 | 19 | 20 | 13B07F861A680F5B00A75B9A 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/ReactNativeART/ios/ReactNativeART/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /examples/ReactNativeART/ios/ReactNativeART/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import "RCTRootView.h" 13 | 14 | @implementation AppDelegate 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 17 | { 18 | NSURL *jsCodeLocation; 19 | 20 | /** 21 | * Loading JavaScript code - uncomment the one you want. 22 | * 23 | * OPTION 1 24 | * Load from development server. Start the server from the repository root: 25 | * 26 | * $ npm start 27 | * 28 | * To run on device, change `localhost` to the IP address of your computer 29 | * (you can get this by typing `ifconfig` into the terminal and selecting the 30 | * `inet` value under `en0:`) and make sure your computer and iOS device are 31 | * on the same Wi-Fi network. 32 | */ 33 | 34 | jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle"]; 35 | 36 | /** 37 | * OPTION 2 38 | * Load from pre-bundled file on disk. To re-generate the static bundle 39 | * from the root of your project directory, run 40 | * 41 | * $ react-native bundle --minify 42 | * 43 | * see http://facebook.github.io/react-native/docs/runningondevice.html 44 | */ 45 | 46 | // jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 47 | 48 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 49 | moduleName:@"ReactNativeART" 50 | initialProperties:nil 51 | launchOptions:launchOptions]; 52 | 53 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 54 | UIViewController *rootViewController = [[UIViewController alloc] init]; 55 | rootViewController.view = rootView; 56 | self.window.rootViewController = rootViewController; 57 | [self.window makeKeyAndVisible]; 58 | return YES; 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /examples/ReactNativeART/ios/ReactNativeART/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /examples/ReactNativeART/ios/ReactNativeART/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /examples/ReactNativeART/ios/ReactNativeART/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UIViewControllerBasedStatusBarAppearance 38 | 39 | NSLocationWhenInUseUsageDescription 40 | 41 | NSAppTransportSecurity 42 | 43 | 44 | NSAllowsArbitraryLoads 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/ReactNativeART/ios/ReactNativeART/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/ReactNativeART/ios/ReactNativeARTTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/ReactNativeART/ios/ReactNativeARTTests/ReactNativeARTTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | #import 12 | 13 | #import "RCTLog.h" 14 | #import "RCTRootView.h" 15 | 16 | #define TIMEOUT_SECONDS 240 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface ReactNativeARTTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation ReactNativeARTTests 24 | 25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 26 | { 27 | if (test(view)) { 28 | return YES; 29 | } 30 | for (UIView *subview in [view subviews]) { 31 | if ([self findSubviewInView:subview matching:test]) { 32 | return YES; 33 | } 34 | } 35 | return NO; 36 | } 37 | 38 | - (void)testRendersWelcomeScreen 39 | { 40 | UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; 41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 42 | BOOL foundElement = NO; 43 | 44 | __block NSString *redboxError = nil; 45 | RCTSetLogFunction(^(RCTLogLevel level, NSString *fileName, NSNumber *lineNumber, NSString *message) { 46 | if (level >= RCTLogLevelError) { 47 | redboxError = message; 48 | } 49 | }); 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | RCTSetLogFunction(RCTDefaultLogFunction); 64 | 65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 67 | } 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /examples/ReactNativeART/ios/main.jsbundle: -------------------------------------------------------------------------------- 1 | // Offline JS 2 | // To re-generate the offline bundle, run this from the root of your project: 3 | // 4 | // $ react-native bundle --minify 5 | // 6 | // See http://facebook.github.io/react-native/docs/runningondevice.html for more details. 7 | 8 | throw new Error('Offline JS file is empty. See iOS/main.jsbundle for instructions'); 9 | -------------------------------------------------------------------------------- /examples/ReactNativeART/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReactNativeART", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node_modules/react-native/packager/packager.sh" 7 | }, 8 | "dependencies": { 9 | "art": "~0.10.0", 10 | "d3": "~3.5.6", 11 | "react-native": "^0.11.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/animate.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/examples/animate.html -------------------------------------------------------------------------------- /examples/animate.js: -------------------------------------------------------------------------------- 1 | import '../src/animate/index'; 2 | -------------------------------------------------------------------------------- /examples/code-share/Component.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Component = React.createClass({ 4 | propTypes: { 5 | count: React.PropTypes.number, 6 | }, 7 | getDefaultProps() { 8 | return { 9 | count: 0, 10 | disabled: true, 11 | }; 12 | }, 13 | getInitialState() { 14 | return { 15 | count: this.props.count, 16 | }; 17 | }, 18 | componentDidMount() { 19 | this.turnOn(); 20 | }, 21 | componentWillReceiveProps(nextProps) { 22 | this.setState({ 23 | count: nextProps.count, 24 | }); 25 | }, 26 | turnOn() { 27 | this.setState({ 28 | disabled: false, 29 | }); 30 | }, 31 | increase() { 32 | this.setState({ 33 | count: this.state.count + 1, 34 | }); 35 | }, 36 | render() { 37 | return ( 38 |
39 |

count

40 | 41 |
42 |

{this.state.count}

43 | 44 |
45 |
46 | ); 47 | }, 48 | }); 49 | 50 | export default Component; 51 | -------------------------------------------------------------------------------- /examples/code-share/Page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | var consolePolyfill = ` 3 | window.process = { 4 | env: {} 5 | }; 6 | (function(global) { 7 | 'use strict'; 8 | global.console = global.console || {}; 9 | var con = global.console; 10 | var prop, method; 11 | var empty = {}; 12 | var dummy = function() {}; 13 | var properties = 'memory'.split(','); 14 | var methods = ('assert,clear,count,debug,dir,dirxml,error,exception,group,' + 15 | 'groupCollapsed,groupEnd,info,log,markTimeline,profile,profiles,profileEnd,' + 16 | 'show,table,time,timeEnd,timeline,timelineEnd,timeStamp,trace,warn').split(','); 17 | while (prop = properties.pop()) 18 | if (!con[prop]) con[prop] = empty; 19 | while (method = methods.pop()) 20 | if (!con[method]) con[method] = dummy; 21 | })(typeof window === 'undefined' ? this : window); 22 | `; 23 | 24 | var app = ` 25 | require('./index'); 26 | `; 27 | 28 | class Page extends React.Component { 29 | render() { 30 | return ( 31 | 32 | 118 | 119 | 120 | 128 | 129 | 130 | ``` 131 | 132 | And example/init.js 133 | 134 | ```javascript 135 | /** @jsx React.DOM */ 136 | 137 | var React = require('react'); 138 | var Router = require('react-router'); 139 | var Route = Router.Route; 140 | var Routes = Router.Routes; 141 | var Redirect = Router.Redirect; 142 | var Link = Router.Link; 143 | 144 | var App = React.createClass({ 145 | render: function() { 146 | return ( 147 |
148 |
    149 |
  • Bob
  • 150 |
  • Sally
  • 151 |
152 | 153 |
154 | ); 155 | } 156 | }); 157 | 158 | var User = React.createClass({ 159 | render: function() { 160 | return ( 161 |
162 |

User id: {this.props.params.userId}

163 |
    164 |
  • foo task
  • 165 |
  • bar task
  • 166 |
167 | 168 |
169 | ); 170 | } 171 | }); 172 | 173 | var Task = React.createClass({ 174 | render: function() { 175 | return ( 176 |
177 |

User id: {this.props.params.userId}

178 |

Task id: {this.props.params.taskId}

179 |
180 | ); 181 | } 182 | }); 183 | 184 | var routes = ( 185 | 186 | 187 | 188 | 189 | 190 | 191 | ); 192 | 193 | React.renderComponent( 194 | , 195 | document.body 196 | ); 197 | ``` 198 | 199 | ## run 200 | 201 | Run the following command first 202 | ``` 203 | bower install modulex # install a browser loader library 204 | npm install # install npm modules 205 | npm start # start local server 206 | ``` 207 | 208 | then open [http://localhost:8000/example/demo.html](http://localhost:8000/example/demo.html) to see the result. 209 | 210 | 211 | ## using browserify 212 | 213 | Add bundle task to gulpfile first 214 | 215 | ```javascript 216 | var gulp = require('gulp'); 217 | var browserify = require('browserify'); 218 | var source = require('vinyl-source-stream'); 219 | gulp.task('bundle', function () { 220 | return browserify(['./init.js']) 221 | .transform(require('reactify')) 222 | .bundle() 223 | //Pass desired output filename to vinyl-source-stream 224 | .pipe(source('init.js')) 225 | // Start piping stream to tasks! 226 | .pipe(gulp.dest('../../example-bundle/react-router/')); 227 | }); 228 | ``` 229 | 230 | Then create demo-bundle.html to use bundled javascript 231 | 232 | ```html 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | ``` 242 | 243 | ## run 244 | 245 | Run ``gulp bundle`` first and then open [http://localhost:8000/example/demo-bundle.html](http://localhost:8000/example/demo-bundle.html) to see the result. 246 | 247 | ### The End 248 | 249 | This is it! Congratulation, you can use browser loader library for quick development and use browserify on production. 250 | The last and most important thing: you can also share code between server and client easily. 251 | 252 | This article is sent to [http://dailyjs.com/2014/11/05/node-roundup/](http://dailyjs.com/2014/11/05/node-roundup/) 253 | -------------------------------------------------------------------------------- /tutorial/en-us/env/setup-your-playground.md: -------------------------------------------------------------------------------- 1 | # set up your playground 2 | 3 | author: yiminghe@gmail.com 4 | 5 | In this article, i will introduce a playground environment where you can test for react demos quickly. 6 | 7 | ## dependent tools 8 | 9 | * [nodejs](http://nodejs.org/) - server side javascript runtime 10 | * [koa](https://github.com/koajs/koa) - a nodejs web framework 11 | * [koa-jsx](https://www.npmjs.org/package/koa-jsx) - koa middleware for transforming jsx of react 12 | * [koa-modularize](https://www.npmjs.org/package/koa-modularize) - koa middleware for transforming commonjs file into browser module format 13 | * [react](https://www.npmjs.org/package/react) - ui library from facebook 14 | * [react-tools](https://www.npmjs.org/package/react-tools) - provide api to transform JSX into vanilla JS 15 | 16 | ## init package.json 17 | 18 | Create package.json at the root of your project directory 19 | 20 | ``` javascript 21 | { 22 | "name": "learning-react", 23 | "version": "1.0.0", 24 | "author": "yiminghe ", 25 | "engines": { 26 | "node": ">=0.11" 27 | }, 28 | "license": "MIT", 29 | "repository": { 30 | "type": "git", 31 | "url": "http://github.com/yiminghe/learning-react.git" 32 | }, 33 | "keywords": [ 34 | "react", 35 | "jsx", 36 | "koa" 37 | ], 38 | "devDependencies": { 39 | "koa": "^0.13.0", 40 | "koa-jsx": "^1.0.0", 41 | "koa-modularize": "^1.0.0", 42 | "koa-mount": "^1.3.0", 43 | "koa-serve-index": "^1.0.1", 44 | "koa-static": "^1.4.7", 45 | "react": "^0.12.0", 46 | "kissy": "~5.0.1", 47 | "react-tools": "^0.12.0" 48 | }, 49 | "scripts": { 50 | "start": "node --harmony server" 51 | } 52 | } 53 | ``` 54 | 55 | Then run ``npm install`` at the root of your project directory. 56 | 57 | ## author your server.js 58 | 59 | Create server.js at the root of your project directory 60 | 61 | ```javascript 62 | var koa = require('koa'); 63 | var serve = require('koa-static'); 64 | var app = koa(); 65 | var path = require('path'); 66 | var cwd = __dirname; 67 | var serveIndex = require('koa-serve-index'); 68 | app.use(serveIndex(cwd, { 69 | hidden: true, 70 | view: 'details' 71 | })); 72 | var jsx = require('koa-jsx'); 73 | app.use(jsx(cwd, { 74 | reactTools: require('react-tools'), 75 | next:function(){ 76 | return 1; 77 | } 78 | })); 79 | var modularize = require('koa-modularize'); 80 | var mount=require('koa-mount'); 81 | app.use(mount('/example',modularize(path.resolve(cwd,'example')))); 82 | app.use(serve(cwd, { 83 | hidden: true 84 | })); 85 | app.listen(8000); 86 | console.log('server start at ' + 8000); 87 | ``` 88 | 89 | ## author your demo 90 | 91 | Place your demo html and commonjs javascript module files into ``example`` folder. 92 | 93 | 94 | ### html file 95 | For example: example/test.html 96 | 97 | ```html 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 113 | 114 | 115 | ``` 116 | 117 | ### js file 118 | For example: example/hello.js 119 | 120 | ```javascript 121 | /** @jsx React.DOM */ 122 | 123 | module.exports = React.createClass({ 124 | render:function(){ 125 | return (
Hello React
); 126 | } 127 | }); 128 | ``` 129 | 130 | For example: example/init.js 131 | 132 | ```javascript 133 | /** @jsx React.DOM */ 134 | 135 | var Hello = require('./hello'); 136 | 137 | React.render(,document.body); 138 | ``` 139 | 140 | Note: the first line must start with ``/** @jsx React.DOM */`` 141 | 142 | ## run demo 143 | 144 | First run ``npm start`` at the root of your project folder, 145 | then open [http://localhost:8000/example/test.html](http://localhost:8000/example/test.html) with your browser. 146 | 147 | Well done! You will see ``Hello React`` on the browser, finally you can modify ``init.js`` and make fun of react now! 148 | -------------------------------------------------------------------------------- /tutorial/en-us/index.md: -------------------------------------------------------------------------------- 1 | # tutorials about React 2 | 3 | - [set up your playground](./env/setup-your-playground.md) 4 | - [using modulex and browserify](./env/modulex-browserify-npm.md) 5 | - [github/react-component spec](https://github.com/react-component/react-component.github.io) 6 | - [object model of react](./internal/object-model.md) 7 | - [harmony in react-tools](./internal/es6-in-harmony.md) 8 | -------------------------------------------------------------------------------- /tutorial/en-us/internal/object-model.md: -------------------------------------------------------------------------------- 1 | # React Object Model 2 | 3 | author: yiminghe@gmail.com 4 | 5 | http://blog.yiminghe.me/2015/04/14/react-object-model/ 6 | 7 | 8 | 9 | 10 | ## Classes and Objects 11 | 12 | ### UserDefinedComponentClass 13 | 14 | user can define custom component class by call React.createClass or extend React.Component 15 | 16 | ```js 17 | class UserDefinedComponentClass extends React.Component{} 18 | 19 | var UserDefinedComponentClass2 = React.createClass(); 20 | ``` 21 | 22 | ### DOMAutoGenerateWrapperClass 23 | 24 | component class represents native DOM nodes 25 | 26 | ```js 27 | // source from react 28 | function autoGenerateWrapperClass(type) { 29 | return ReactClass.createClass({ 30 | tagName: type.toUpperCase(), 31 | render: function() { 32 | // Copy owner down for debugging info 33 | var internalInstance = ReactInstanceMap.get(this); 34 | return new ReactElement( 35 | type, 36 | null, // key 37 | null, // ref 38 | internalInstance._currentElement._owner, // owner 39 | null, // context 40 | this.props 41 | ); 42 | } 43 | }); 44 | } 45 | ``` 46 | 47 | ### ReacCompositeComponentWrapper 48 | 49 | React internal class for render custom component and DOM component to native platform. 50 | 51 | ### ReactDOMComponent 52 | 53 | React internal class for render DOM component to native platform in the end. 54 | 55 | ### ReactElement/element 56 | 57 | class for virtual DOM node (element), element's type field will be the paramter passed to React.createElement. 58 | 59 | ```js 60 | var custom = ; //React.createElement(My); 61 | var div=
;//React.createElement('div'); 62 | div instanceof ReactElement //true 63 | custom instanceof ReactElement //true 64 | ``` 65 | 66 | 67 | 68 | ### instance 69 | 70 | instance of UserDefinedComponentClass or DOMAutoGenerateWrapperClass, it links to React internal class instance by _reactInternalInstance field. 71 | 72 | 73 | ### reactInternalInstance 74 | 75 | there are two types of React internal class instance: compositeComponent and domComponent. 76 | 77 | #### compositeComponent 78 | 79 | element will link to it by _owner field. owner is the component which element is created from its render() method. 80 | 81 | It also link to component class instance by _instance field, instance and reactInternalInstance are 1-1. 82 | 83 | It links to React internal class instance transformed from its render() method's return value by _renderComponent field, so render method can not return array. 84 | 85 | ## domComponent 86 | 87 | In the end, it all goes to domComponent, dom component will render its children recursively(_renderedChildren), each of its children is a React internal class instance. 88 | 89 | ```js 90 |
// domComponent 91 | // domComponent 92 | 1 // domTextComponent 93 | 94 | // compositeComponent 95 |
96 | ``` 97 | -------------------------------------------------------------------------------- /tutorial/en-us/internal/object-model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/tutorial/en-us/internal/object-model.png -------------------------------------------------------------------------------- /tutorial/en-us/internal/object-model.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiminghe/learning-react/1b541e47021f4e7f5ffff413e6d0fd9440a13ca0/tutorial/en-us/internal/object-model.sketch -------------------------------------------------------------------------------- /tutorial/zh-cn/advanced.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | react 进阶 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 32 | 33 | 36 | 37 | 42 | 43 | 44 | 45 | 46 |
47 | 48 |
49 |
50 |

React 进阶

51 | 52 |

53 | yiminghe@gmail.com 54 |

55 |
56 | 57 |
58 |

进阶

59 | 60 |
    61 |
  • 生态圈
  • 62 |
  • 开发工具
  • 63 |
  • 如何开发一个组件
  • 64 |
  • 如何开发项目
  • 65 |
66 |
67 | 68 |
69 |
70 |

生态圈

71 | 72 |

73 | 安装 nodejs: 请使用 nvm 安装 74 | 4.0 75 |

76 | 77 |

78 | tnpm 79 |

80 |
81 |
82 |

安装生态圈模块

83 | 84 |

 85 | npm install xx
 86 | tnpm install yy
 87 | tnpm install @your-company/xx
 88 |                 
89 |
90 |
91 | 92 |
93 |

开发工具

94 | 95 |

96 | 组件开发: 97 |

98 |

 99 |                 tnpm install yo generator-rc -g
100 |             
101 |

102 | 项目开发: 103 |

104 |

105 |                 tnpm install antd-init -g
106 |             
107 |
108 | 109 |
110 |
111 |

如何开发一个组件

112 | 113 |

初始化

114 | 115 |

开发调试

116 | 117 |

单元测试

118 | 119 |

发布

120 | 121 | 124 |
125 | 126 |
127 |

初始化

128 | 129 |
yo rc --author=chengyu@your-company.com
130 |                     --pkg_name=@your-company/xx
131 |                     --tnpm
132 |                     --port=8000
133 |                     --repo_url='http://gitlab.com/xx'
134 | 135 |

136 | author: 作者邮箱 137 |

138 | 139 |

140 | pkg_name: 包名,默认为 rc- 加目录名 141 |

142 | 143 |

144 | tnpm: 是否发布到 tnpm 145 |

146 | 147 |

148 | port: 调试端口 149 |

150 | 151 |

152 | repo_url: 代码库地址 153 |

154 |
155 | 156 |
157 |

初始化目录结构

158 | 159 |
160 |
161 |

assets: 样式源码,less 语法

162 | 163 |

examples: 示例代码,页面为空,纯 react 渲染

164 | 165 |

src: 源码文件,es2015

166 | 167 |

tests: 单元测试,纯 js

168 | 169 |

package.json, README.md 按需修改

170 |
171 |
172 | 174 |
175 |
176 |
177 | 178 |
179 |

源码 src

180 | 181 |

182 | es2015 183 |

184 | 185 |

186 | import React from 'react';
187 | const Menu = React.createClass({
188 |     render(){}
189 | });
190 | export default Menu;
191 |                 
192 |
193 | 194 |
195 |

examples

196 | 197 |

纯 js,渲染示例到留空的 __react-content div

198 | 199 |

200 | import React from 'react';
201 | import Menu from '@your-company/biz-menu';
202 | import '@your-company/biz-menu/assets/index.less';
203 | React.render(<Menu />,
204 | document.getElementById('__react-content'));
205 |                 
206 |
207 | 208 |
209 |

tests

210 | 211 |

212 | 使用 mocha/expect.js 编写 spec js 文件,可使用 React.addons.TestUtils 套件 213 |

214 | 215 |

216 | import React from 'react';
217 | import Menu from '@your-company/biz-menu';
218 | import '@your-company/biz-menu/assets/index.less';
219 | var TestUtils = React.addons.TestUtils;
220 | describe('@your-company/biz-menu', () => {
221 |     it('works', () => {
222 |         var instance = TestUtils.renderIntoDocument(React.createElement(Menu));
223 |         expect(TestUtils.scryRenderedDOMComponentsWithClass('.rc-menu-item')).to.be.ok();
224 |     });
225 | });
226 |                 
227 |
228 | 229 |
230 |

演示与测试

231 | 232 |

233 | npm start // 启动调试服务器
234 | 
235 | http://localhost:8000/examples/ // demo 查看
236 | 
237 | http://localhost:8000/tests/runner.html // 测试用例
238 | 
239 | http://localhost:8000/node_modules/rc-server/node_modules/node-jscover/lib/front-end/jscoverage.html?
240 | w=http://localhost:8000/tests/runner.html?coverage
241 | 
242 | npm run browser-test // phantomjs 运行测试用例
243 | 
244 | npm run browser-test-cover // phantomjs 运行测试覆盖率
245 | 
246 | npm run karma // 多浏览器测试
247 |                 
248 |
249 | 250 |
251 |

发布

252 | 253 |

npm run pub / npm run pub -- --tnpm

254 |
255 |
256 | 257 |
258 |

如何开发一个项目

259 |
    260 |
  • 纯前端
  • 261 |
  • chair
  • 262 |
263 |
264 | 265 |
266 |
267 |

纯前端项目

268 | 269 |

270 |                     antd-init
271 |                 
272 |
273 |
274 |

package.json

275 |

276 | {
277 |     "entry": {
278 |         "index": "./index.js"
279 |     },
280 |     "dependencies": {
281 |         "antd": "*",
282 |         "antd-build": "0.4.x",
283 |         "react": "~0.14.0",
284 |         "react-dom": "~0.14.0"
285 |     },
286 |     "devDependencies": {
287 |         "antd-bin": "0.x"
288 |     },
289 |     "scripts": {
290 |         "start": "antd server",
291 |         "build": "antd-build"
292 |     }
293 | }
294 |                 
295 | 296 |

297 | entry: 入口文件集合 298 |

299 |
300 | 301 |
302 |

一个应用页面 index.html

303 | 304 | 305 |
306 | 307 |
308 |

入口文件

309 | 310 |

311 | index.js: 引用依赖,渲染 react 组件到页面空位 312 |

313 |

314 | import React from 'react';
315 | import '../common/lib';
316 | import Datepicker from 'antd/lib/datepicker';
317 | 
318 | class App {
319 |     render(){
320 |         return <Datepicker />;
321 |     }
322 | }
323 | 
324 | React.render(<App />, document.getElementById('react-content'));
325 |                 
326 |
327 | 328 |
329 |

按需加载

330 | 331 |

通过 AMD 的语法格式进行动态加载

332 |

333 | require(['x','y'], function(X, Y){
334 | // x y 模块进行了动态加载
335 | });
336 |                 
337 |
338 | 339 |
340 |

调试开发

341 |

342 | npm start
343 |                 
344 | 345 |

346 | 访问 http://localhost:8000/index.html 347 |

348 |
349 | 350 |
351 |

发布

352 | 353 |

354 | npm run build
355 |                 
356 | 357 | 358 |
359 |
360 |

版本号目录

361 | 362 |

363 | {
364 | "build": "rm -rf dist && antd build && mkdir -p dist/${npm_package_name}/${npm_package_version} && mv dist/*.* dist/${npm_package_name}/${npm_package_version}/"
365 | }
366 |                 
367 | 368 |

369 | TODO: hash vm 映射 370 |

371 |
372 |
373 | 374 |
375 |
376 |

chair

377 | 378 |

379 | tnpm install chair-init -g
380 | 
381 | chair init --type react test
382 |                 
383 |
384 | 385 |
386 |

入口文件约定

387 | 388 |

app/assets/entry/index.jsx

389 |

390 | var React  = require('react');
391 | var appData = require('appData'); // 服务器端数据
392 | React.render(<div>
393 | react {appData.fromServer}
394 | </div>,document.getElementById('react-content'));
395 |                 
396 |
397 | 398 |
399 |

app/controllers/home.js 启动渲染

400 | 401 |

402 | var render = require('../views/render');
403 | this.body = render(this, {
404 |     entry: 'index',
405 |     appData: {fromServer: 'database'}
406 | });
407 |             
408 |
409 |
410 | 411 |
412 |
413 |

router

414 | 415 |

客户端路由

416 | 417 |

418 | demo: 419 | http://yiminghe.me/learning-react/examples/react-router.html 420 | 421 |

422 |
423 | 424 |
425 |

react-router

426 | 427 |

将 url 嵌套同组件嵌套关联起来

428 | 429 |

/ -> App/Index

430 | 431 |

/state/x -> App/State

432 | 433 |

/x -> App/Index

434 |
435 | 436 |
437 |

react-router api

438 | 439 |
    440 |
  • this.props.children: 嵌套组件
  • 441 |
  • this.props.params: url 参数
  • 442 |
  • this.props.query: url 请求参数
  • 443 |
444 |
445 |
446 | 447 |
448 |

作业

449 | 450 |

search - list

451 |
452 | 453 |
454 |

Thanks

455 |
456 |
457 |
458 | 459 | 460 | 461 | 501 | 502 | 503 | 504 | -------------------------------------------------------------------------------- /tutorial/zh-cn/component/code-style/comment.md: -------------------------------------------------------------------------------- 1 | # js 注释规范 2 | 3 | ## 总原则 4 | 5 | 1. **As short as possible(如无必要,勿增注释)**。尽量提高代码本身的清晰性、可读性。 6 | 1. **As long as necessary(如有必要,尽量详尽)**。合理的注释、空行排版等,可以让代码更易阅读、更具美感。 7 | 8 | 总之,注释的目的是:**提高代码的可读性,从而提高代码的可维护性。** 9 | 10 | 11 | ## 什么时候需要添加注释 12 | 13 | 1. 某段代码的写法,需要注释说明 why 时: 14 | ```js 15 | // Using loop is more efficient than `rest = slice.call(arguments, 1)`. 16 | for (i = 1, len = arguments.length; i < len; i++) { 17 | rest[i - 1] = arguments[i]; 18 | } 19 | ``` 20 | 21 | 2. 添加上注释,能让代码结构更清晰时: 22 | ```js 23 | init: function(selector, context, rootjQuery) { 24 | var match, elem, ret, doc; 25 | 26 | // Handle $(""), $(null), or $(undefined) 27 | if ( !selector ) { 28 | ... 29 | } 30 | 31 | // Handle $(DOMElement) 32 | if ( selector.nodeType ) { 33 | ... 34 | } 35 | 36 | // The body element only exists once, optimize finding it 37 | if ( typeof selector === "string" ) { 38 | ... 39 | } 40 | } 41 | ``` 42 | 43 | 3. 有借鉴第三方代码,需要说明时: 44 | ```js 45 | // Inspired by https://github.com/jquery/jquery/blob/master/src/core.js 46 | function ready() { 47 | ... 48 | } 49 | ``` 50 | 51 | 52 | ## 文件起始处的约定 53 | 54 | 每个源码文件的开头为 /** @jsx React.DOM */ ,第二行保留为空: 55 | 56 | ```js 57 | /** @jsx React.DOM */ 58 | 59 | // 源代码 60 | 61 | ``` 62 | 63 | 注意点: 64 | 65 | 1. 文件头不添加作者信息,是因为更推崇团队和社区参与。author 和 contributors 信息,在 GitHub 上可以清晰看出来。(注意:该条规范,仅适用于通用组件。对于业务代码,请添加上作者信息,以便在出问题时,快速找到负责人。) 66 | 1. 文件最后空一行,可以保证在 combo 合并后,源码的层次清晰。 67 | 68 | 69 | ## 注释书写规范 70 | 71 | 1. 源码中的注释,推荐用英文。 72 | 1. 含有中文时,标点符号用中文全角。 73 | 1. 中英文夹杂时,英文与中文之间要用一个空格分开。 74 | 1. 注释标识符与注释内容要用一个空格分开:`// 注释` 与 `/* 注释 */`。 75 | 76 | 77 | ## JSDoc 注释 78 | 79 | - 不推荐 JSDoc 式注释,推荐 Backbone 风格的注释。 80 | - API 请通过 README 等文档表达清楚。 81 | - 不写 JSDoc 类文档,可以让开发者在写代码时更专注于写代码,在写文档时则更专注于写文档。**让工作解耦,更专注。** 82 | 83 | 84 | ## 相关 85 | 86 | - https://github.com/aralejs/aralejs.org/wiki/JavaScript-注释规范 87 | -------------------------------------------------------------------------------- /tutorial/zh-cn/component/code-style/css.md: -------------------------------------------------------------------------------- 1 | # css 源码规范 2 | 3 | 4 | ## 基础 5 | - 样式采用 less 语法 6 | - 建议直接用 bootstrap,bootstrap 没的自己写在 assets/bootstrap.less 中 7 | - 如果有独立样式则以 rc 为命名空间 8 | - 如果样式有依赖其他组件,需要建立对应的 js,例如 assets/bootstrap.js 9 | 10 | ```js 11 | require('xx/assets/yy.css'); // depend other component's css 12 | require('./bootstrap.css'); 13 | ``` 14 | 15 | ## 文件命名 16 | 17 | - less 文件名推荐和 js 文件名对应,例如 lib/TimePanel.js 对应 assets/bootstrap/TimePanel.less 18 | - index.less 等入口文件名小写,推荐里面只 import 对应的 less 源码 19 | 20 | ## 语义化 21 | 22 | 如 rc-tab、rc-nav,不要使用 red、left 等表象的词命名。 23 | 24 | ## 类名有前缀 25 | 26 | ```html 27 |
28 |

dialog header

29 |

dialog body

30 |
31 | ``` 32 | 33 | 子模块: {命名空间}-{模块名}-{子模块名} 常用模块名有:bd(body),cnt(content),hd(header),text(txt),img(images/pic),title,item,cell 等, 词义表达组件要实现的功能。 34 | 35 | 上面的代码中,模块的名为 dialog,模块最外层使用 {命名空间}-{模块名} 的方式命名 Class。 36 | 模块子元素以在此基础上进行命名。如果不继承父级的类名,很容易造成命名冲突。 37 | 38 | ## 避免不必要的 CSS 选择符嵌套 39 | 40 | Class 已经模块化命名,从类名上已经可以清晰的分辨元素的从属,一般情况下也不会造成类名冲突,没有必要再进行选择器嵌套,保持 css 结构清晰,提高渲染效率。特殊情况可以嵌套(如提高权重、主题之间代码隔离),但应避免过多层级。 41 | 42 | ``` 43 | /* 推荐写法 */ 44 | .rc-dialog { 45 | border: 1px solid #333; 46 | } 47 | 48 | .rc-dialog-hd { 49 | margin: 0; 50 | padding: 5px 10px; 51 | border-bottom: 1px solid #333; 52 | background-color: #CCC; 53 | } 54 | 55 | .rc-dialog-bd { 56 | margin: 10px; 57 | } 58 | 59 | /* 不推荐写法 */ 60 | .rc-dialog .rc-dialog-hd {} 61 | .rc-dialog .rc-dialog-bd {} 62 | ``` 63 | 64 | ## 状态 65 | 66 | 模块状态: {命名空间}-{模块名}-{状态描述} 常用状态有:hover, current, selected, disabled, focus, blur, checked, success, error 等 67 | 68 | 与 JS 交互时,在模块 HTML 结构的最外一层添加状态,而非给模块每个子元素单独添加元素。给最外层添加状态类以后,整个模块的样式都能控制,减少操作,提高性能。 69 | 70 | ``` 71 |
72 |

dialog header

73 |

dialog body

74 |
75 | ``` 76 | 77 | ## 去除浏览器前缀 78 | 79 | 不要加 `-webkit-` `-moz-` 等浏览器前缀,工具会自动添加. 80 | 81 | ## 统一风格 82 | 83 | 统一命名风格(使用相同名词命名不同组件的子元素):如 rc-tab-hd, rc-modal-hd,便于理解。 84 | 85 | ## 进一步 86 | 87 | BEM css 命名规划 88 | 89 | ## 参考 90 | 91 | - http://aliceui.org/docs/rule.html 92 | - http://google-styleguide.googlecode.com/svn/trunk/htmlcssguide.xml 93 | - http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/ 94 | -------------------------------------------------------------------------------- /tutorial/zh-cn/component/code-style/js.md: -------------------------------------------------------------------------------- 1 | # js 编码规范 2 | 3 | 代码通过 jshint(在根目录运行 `npm run lint`),熟悉规范参见如下 4 | 5 | ## 具体书写规范 6 | 7 | --- 8 | 9 | 下面是一些常用注意点: 10 | 11 | 12 | ### 编码 13 | 14 | 统一用 utf-8 15 | 16 | 17 | ### 长度 18 | 19 | 长度不超过 80 个字符。别小看这一条规则,如果严格去遵循,你会发现代码变清晰了。而且,你一定能做到的。 20 | 21 | 参考: 22 | 23 | 1. pep8 为 79 个字符 24 | 2. npm 为 80 个字符 25 | 3. google 为 80 个字符 26 | 27 | 28 | ### 缩进 29 | 30 | 缩进使用 2个空格,组件内保持统一,不混用。禁用 tab。 31 | 32 | 参考: 33 | 34 | 1. npm 为 2 空格 35 | 2. pep8 为 4 空格 36 | 3. google 为 2 空格( gjslint 没规定) 37 | 38 | 39 | 40 | ### 花括号 41 | 42 | #### 花括号不换行 43 | 44 | 好 45 | 46 | ```` 47 | if (foo) { 48 | } 49 | ```` 50 | 51 | 坏 52 | 53 | ```` 54 | if (foo) 55 | { 56 | } 57 | ```` 58 | 59 | **不允许一行判断,一律换行** 60 | 61 | 坏 62 | 63 | ```` 64 | if (foo) return; 65 | ```` 66 | 67 | ###命名约定 68 | 69 | 1. 常量 UPPERCASE_WORD 70 | 2. 变量 camelName 71 | 3. 类名 CamelName 72 | 73 | 74 | ### 空格 75 | 76 | #### 操作符之间需要空格 77 | 78 | 好 79 | 80 | ```` 81 | var x = y + z; 82 | ```` 83 | 84 | 坏 85 | 86 | ```` 87 | var x=y+z 88 | ```` 89 | 90 | #### 只空一格 91 | 92 | 好 93 | 94 | ```` 95 | { 96 | a: 'short', 97 | looooongname: 'long' 98 | } 99 | ```` 100 | 101 | 坏 102 | 103 | ```` 104 | { 105 | a : 'short', 106 | looooongname: 'long' 107 | } 108 | ```` 109 | 110 | ### 逗号与换行 111 | 112 | 建议用自然人的处理方法 113 | 114 | ```` 115 | { 116 | a: 'a', 117 | b: 'b', 118 | c: 'c' 119 | } 120 | ```` 121 | 122 | 不建议使用 npm 风格的逗号与换行,即 123 | 124 | ```` 125 | { 126 | a: 'a' 127 | ,b: 'b' 128 | ,c: 'c' 129 | } 130 | ```` 131 | 132 | 133 | ### 变量声明 134 | 135 | 首先,**变量在使用前必须声明**。 136 | 137 | 对于单 var 模式和多 var 模式,不做强行约定,但同一个文件里,风格必须一致。 138 | 139 | ## 文件命名 140 | 141 | - js 模块采用 commonjs 格式,主体代码放在 lib 目录下,根目录 index.js 仅引用 lib 下相关文件 142 | - lib 目录模块如果返回值是个类,则文件名首字母大写 143 | - 测试用例文件名以 .spec.js 结尾 144 | - 测试用例文件名推荐和 lib 下源码对应,比如 lib/Calendar.js 对应于 tests/Calendar.spec.js 145 | - 测试用例入口文件名为 index.spec.js,推荐里面只 require 其他测试用例 146 | 147 | ## 代码格式 148 | 149 | - log 使用 2.x debug 模块,不可以使用 console.log 150 | ```js 151 | var debug = require('debug'))('rc-menu'); 152 | debug('xxx'); 153 | ``` 154 | - 公共包通过 npm install 后,js 中可以 require node_modules 下的公共包 js,但不可以 require css 155 | - 使用 propType 制定 react 组件属性的类型 156 | - 只能 require('react') 不可以 require('react/addons') 以及 require('react/lib/xx') 157 | - 禁止使用 jquery 等大而全的类库 158 | - React 类必须用一个变量声明 159 | 160 | Menu.js 161 | ```js 162 | var React = require('react'); 163 | var Menu = React.createClass({ 164 | propTypes: { 165 | active: React.PropTypes.bool 166 | } 167 | }); 168 | module.exports = Menu; 169 | ``` 170 | 171 | - 组件根节点样式名默认为 rc- 加上小写组件名,组件名单词间以 - 分隔,允许通过 prefixCls 定制 172 | - 组件内部的样式名都要以 prefixCls 为前缀 173 | - 组件允许用户通过 className 定制样式名 174 | 175 | ```js 176 | var Menu = React.createClass({ 177 | render: function(){ 178 | var prefixCls = this.props.prefixCls; 179 | var className = prefixCls || "rc-menu"; 180 | if(this.props.className){ 181 | className += ' '+this.props.className; 182 | } 183 | return (
TODO
); 184 | } 185 | }); 186 | ``` 187 | 188 | - 组件是 react-component 而不是 react-bootstrap,不要把一些bootstrap的样式生搬过来,例如 189 | 190 | ```js 191 | var Dialog = React.createClass({ 192 | render: function(){ 193 | return
194 |
195 |
196 | } 197 | }); 198 | ``` 199 | 200 | 组件和 bootstrap css 绑定过紧,样式和 js 不一致,建议通过属性来解决: 201 | 202 | ```js 203 | var Dialog = React.createClass({ 204 | render: function(){ 205 | var prefixCls = this.props.prefixCls; 206 | return
207 |
208 |
209 | } 210 | }); 211 | 212 | 213 | ``` 214 | 215 | ## 参考 216 | 217 | - https://github.com/aralejs/aralejs.org/wiki/UI-%E7%BB%84%E4%BB%B6%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%B7%E5%BC%8F 218 | - https://github.com/aralejs/aralejs.org/wiki/JavaScript-编码风格 219 | - https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml 220 | -------------------------------------------------------------------------------- /tutorial/zh-cn/component/component-code-style.md: -------------------------------------------------------------------------------- 1 | # react 组件代码规范 2 | --- 3 | 4 | author: yiminghe@gmail.com 5 | 6 | ## 细则 7 | 8 | ### 总体 9 | 10 | - 使用 generator-rc, rc-tools, rc-server 基础设施 11 | - 组件需要支持 travis, coveralls, saucelabs, npm, spm 12 | - 组件功能点需要有测试用例,示例,js 源码,可选的 css 源码 13 | 14 | ### js 源码 15 | 16 | 详见 [js 源码规范](./code-style/js.md) 17 | 18 | ### js 注释 19 | 20 | 详见 [js 注释规范](./code-style/comment.md) 21 | 22 | ### css 源码 23 | 24 | 详见 [css 源码规范](./code-style/css.md) 25 | 26 | ### examples 27 | 28 | - examples 中的 html 不可修改,通过 js 中的 jsx 渲染页面,通过 require css 引入 css 29 | - \`\`\`\`js 中的 js 代码为 commonjs 格式,第一行为注释 `/** @jsx React.DOM */` 30 | 31 | ```js 32 | \````js 33 | /** @jsx React.DOM */ 34 | require('rc-menu/assets/index.css'); 35 | var Menu = require('rc-menu'); 36 | React.render(, document.getElementById('react-content')); 37 | \```` 38 | ``` 39 | 40 | 通过 npm run gh-pages 来发布 examples 到外网(需要同级clone xx-gh-pages ,详见 gh-pages.sh) 41 | 42 | ### tests 43 | 44 | - 代码位于 `tests/xx.spec.js` `index.spec.js` 为必须,里面可以 require 其他 spec 45 | - 测试用例 js 采用 commonjs 格式,可以 require node_modules 下的公共包的 js 和 css 46 | - 可以 require('react') 以及 require('react/addons') 47 | - 测试框架为 mocha,断言库为 expect.js 48 | 49 | ## 示例 50 | 51 | 以上规则示例参考: https://github.com/react-component/calendar 52 | -------------------------------------------------------------------------------- /tutorial/zh-cn/component/component-design.md: -------------------------------------------------------------------------------- 1 | # react 组件设计原则 2 | 3 | ## 职责清晰 4 | 5 | 多个组件协同完成一件事情,而不是一个组件替其他组件完成本该它自己完成的事情。例如 6 | 7 | ``` 8 | // menu1 9 | 10 | 11 | // menu2 12 | 13 | 14 | 15 | ``` 16 | 17 | menu1 只应该关心当前 children 中谁是当前高亮项(active),而不应该关注 SubMenu 是否应该展开子菜单(SubMenu 应该由自己是否是 active 决定是否展开子菜单) 18 | 19 | 20 | ## 扁平访问 21 | 22 | 组件推荐使用状态来控制交互和显示,如果需要显示访问,也尽量实行扁平访问,即只可以调用其 children 的方法。例如 23 | 24 | ``` 25 | // menu1 26 | 27 | 28 | // menu2 29 | 30 | 31 | 32 | ``` 33 | 34 | 当 menu1 处理键盘事件时,应该事件转发给其 children 处理. 35 | 36 | 正确 37 | 38 | menu: 39 | ``` 40 | children.forEach(function(c){ 41 | c.handleKeyDown(e); 42 | }); 43 | ``` 44 | 45 | submenu: 46 | ``` 47 | handleKeyDown: function(e){ 48 | if(e.keyCode ==''){ 49 | this.refs.menu.setState({show:1}); 50 | } 51 | } 52 | ``` 53 | 54 | 错误: 55 | 56 | menu: 57 | ``` 58 | children.forEach(function(c){ 59 | if(c.type===SubMenu){ 60 | if(e.keyCode ==''){ 61 | c.refs.menu.setState({show:1}); 62 | } 63 | } 64 | }); 65 | ``` 66 | 67 | 该示例也应用于第一条 68 | 69 | ## 信息冗余 70 | 71 | 尽量避免信息冗余,如果某个 state 可以由其他 state 计算得到,那么就删除这个 state,例如 72 | 73 | 错误 74 | 75 | ``` 76 | getInitialState: function(){ 77 | return { 78 | fullName: this.props.firstName + this.props.lastName; 79 | } 80 | } 81 | 82 | render: function(){ 83 | return {this.state.fullName} 84 | } 85 | ``` 86 | 87 | 正确 88 | 89 | ``` 90 | render: function(){ 91 | return {this.props.firstName + this.props.lastName} 92 | } 93 | ``` 94 | 95 | ## api 尽量和已知概念保持一致 96 | 97 | 如果 api 可以和已知概念保持一致,那么就用已知的 api 98 | 99 | 错误 100 | 101 | ``` 102 | 103 | 104 | 105 | 106 | ``` 107 | 108 | eventKey 用来唯一标示 tabs 的 tabpane,同时 tabs 通过 activeKey 来匹配 eventKey 来确定哪个 tabpane 是当前 active 的。 109 | 110 | 正确 111 | 112 | ``` 113 | 114 | 115 | 116 | 117 | ``` 118 | 119 | 我们可以复用 key 的 api,key 唯一标示了 tabs 的 某个 tabpane,并且对于后期更新也更高效 120 | 121 | ## 使用标签嵌套 122 | 123 | 尽量使用标签嵌套而不是属性配置。 124 | 125 | 错误: 126 | 127 | ``` 128 | 1}, {tab:'t2',pane:2}]}/> 129 | ``` 130 | 131 | 正确 132 | 133 | ``` 134 | 135 | 1 136 | 2 137 | 138 | ``` 139 | 140 | ## 避免使用 ref 141 | 142 | 使用父组件的 state 控制子组件的状态而不是直接通过 ref 操作子组件 143 | 144 | 错误 145 | 146 | ``` 147 | { 148 | handleClick(){ 149 | this.refs.x.setState({count:count}); 150 | } 151 | 152 | render(){ 153 | return
154 | 155 |
156 | } 157 | } 158 | ``` 159 | 160 | 正确 161 | 162 | ``` 163 | { 164 | handleClick(){ 165 | this.setState({count:count}); 166 | } 167 | 168 | render(){ 169 | return
170 | 171 |
172 | } 173 | } 174 | ``` 175 | -------------------------------------------------------------------------------- /tutorial/zh-cn/component/how-to-write-a-react-component.md: -------------------------------------------------------------------------------- 1 | # 如何写一个 react 组件 2 | --- 3 | 4 | author: yiminghe@gmail.com 5 | 6 | ## 建立组件 git 库 7 | 8 | - https://github.com/react-component 9 | 10 | ## 搭建脚手架 11 | 12 | - 使用 https://github.com/react-component/generator-rc 搭建脚手架 13 | 14 | ### 目录结构 15 | 16 | ``` 17 | - .travis.yml 18 | - examples 19 | - index.js 20 | - index.html 21 | - lib 22 | - Component.js 23 | - index.js 24 | - tests 25 | - index.spec.js 26 | - package.json 27 | ``` 28 | 29 | ## 源码 30 | 31 | - 在 lib 目录中写 js,在 assets 目录下写 less,在 tests 目录下写 测试用例,代码规范参考 [react 组件代码规范](./component-code-style.md). 32 | - examples 中的 html 不可修改,通过 js 中的 jsx 渲染页面,通过 require css 引入 css 33 | - 开发中用到其他公共库,通过 `npm install --save` 以及 `npm install --save-dev` 来安装 34 | - 组件设计可参考 [react 组件设计原则](./component-design.md). 35 | 36 | ## 启用开源平台服务 37 | 38 | ### travis-ci 39 | 40 | 使用 github 账号登陆 travis 后访问 http://https://travis-ci.org/profile 开启对应 git 库 41 | 42 | ### coveralls.io 43 | 44 | 使用 github 账号登陆 coveralls 后访问 https://coveralls.io/repos/new 开启对应 git 库 45 | 46 | ### saucelabs.com 47 | 48 | - 访问 https://saucelabs.com/opensauce 注册对应 npm 包名的账号, 49 | - 以该账号登陆后,访问 https://docs.saucelabs.com/ci-integrations/travis-ci/ 50 | - 在库根目录执行 `gem install travis` (需要[设置 gem 镜像](https://ruby.taobao.org/)) 和上述网页中的两个 `travis encrypt` 命令 51 | - 修改 .travis.yml 在 script 区域加入 `- npm run saucelabs` 52 | 53 | ## 开发调试 54 | 55 | - 在项目根目录执行 `npm install` 56 | - 在项目根目录执行 `npm start` 57 | - 打开 `http://localhost:xxxx` 访问库, xxxx 为脚手架配置的网络端口 58 | - 打开 `http://localhost:xxxx/examples/index.html` 查看示例 59 | - 打开 `http://localhost:xxxx/tests/runner.html` 运行测试 60 | 61 | ## 支持 spm 62 | 63 | - npm install spm -g 64 | - 修改 package.json 将源码中用到的库,从 dependencies 字段复制到 spm 字段 65 | 66 | ```js 67 | { 68 | "devDependencies":{ 69 | "react": "0.12.x" 70 | }, 71 | "spm":{ 72 | "dependencies":{ 73 | "react": "0.12.x" 74 | } 75 | } 76 | } 77 | ``` 78 | 79 | ## 浏览器支持版本 80 | 81 | - ie8, ie8+, chrome, firefox 最新版 82 | - 可适当渐进降级,如 css 动画可以不支持 ie8 83 | 84 | ## 功能要求 85 | 86 | - 支持基本的键盘访问,最好支持 [WAI-ARIA](http://www.w3.org/TR/wai-aria/) 87 | 88 | ## 支持 HISTORY.md 89 | 90 | - 通过在根目录运行 `npm run history` 生成 HISTORY.md 91 | - 需要建立必要的 milestone,issue,label,参见: https://github.com/yiminghe/gh-history 92 | - milestone 标题为语义化版本号,issue 属于某个 milestone,并且具备 label 93 | - label 为枚举,包括 94 | - `new` 新增的属性、功能、方法、特性等等 95 | - `fixed` 修复 bug 和影响使用的性能问题等 96 | - `improved` 接口增强、健壮性和性能提升、代码优化、依赖模块升级等。 97 | - `changed` 涉及到兼容性变化的改动。 98 | 99 | ## 发布 100 | 101 | - 在根目录运行 npm publish 102 | -------------------------------------------------------------------------------- /tutorial/zh-cn/component/kissy-react-compare.md: -------------------------------------------------------------------------------- 1 | # kissy 与 react 组件编写异同 2 | 3 | `react` 在传统组件架构的基础上增加了创新性的 `虚拟 dom` 和 `diff` 算法,减少了传统组件架构的手动局部渲染问题,并使用类似 html 的 `jsx` 语法来构建组件,配合极简的 api,概念很少,入门很快。 4 | 5 | 本文将介绍如何从传统的组件架构 KISSY 迁移到 react。示例组件为 `menu` 以及 `calendar/date-picker` 6 | 7 | kissy menu: https://github.com/kissyteam/menu 8 | react menu: https://github.com/react-component/menu 9 | 10 | kissy date-picker: https://github.com/kissyteam/date-picker 11 | react calendar: https://github.com/react-component/calendar 12 | 13 | ## 目录结构 14 | 15 | 以 `calendar/date-picker` 举例,打开 `lib` 目录可见,组织基本相同,calendar 包括日选择面板以及弹出的月,年,年代选择面板,由四个组件组成: 16 | kissy 对应为 `date-picker.js` `decade-panel.js` `month-panel.js` `year-panel.js` 17 | react 对应为 `Calendar.js` `DecadePanel.js` `MonthPanel.js` `YearPanel.js` 18 | 19 | ### 组件设计 20 | 21 | #### API 22 | 23 | kissy: 24 | 25 | ```js 26 | new DatePicker({ 27 | ... 28 | }).render(container); 29 | 30 | new Menu({ 31 | ... 32 | children:[{ 33 | new MenuItem(…) 34 | }] 35 | }).render(container) 36 | ``` 37 | 38 | react: 39 | 40 | ```js 41 | React.render(, container); 42 | React.render(,container) 43 | ``` 44 | 45 | api 有很大的相似性,都支持属性,组合等特性,但是 react 将 dom 和组件统一了起来,从而比 kissy 达到更强的一致性: 46 | 47 | ```js 48 | React.render(
dom
, container); 49 | ``` 50 | 51 | #### 状态与属性 52 | 53 | kissy 实际上不区分状态与属性,都是通过 `attr` 来声明:https://github.com/kissyteam/date-picker/blob/2622151aa29ef0c3f2b7d1c541b91699fe105298/lib/date-picker.js#L492 54 | 55 | 因而需要文档可说明,哪些只能初始化 `config` 的,哪些可以后期 `set`。 56 | 57 | 而 react 通过 `props` 和 `state` 来区分可以 `config` 的属性以及后期可以 `set(setState)` 的属性。 58 | 59 | #### 模版 60 | 61 | kissy 的组件架构为传统的 `mvc` 架构,`v` 采用 `xtemplate` 模版,因此 kissy 有单独的 `xtpl` 目录用于存放组件的模版,例如 62 | 63 | https://github.com/kissyteam/date-picker/blob/2622151aa29ef0c3f2b7d1c541b91699fe105298/lib/date-picker/xtpl/picker.xtpl 64 | 65 | 其中又有组件自身实现的一些命令从而打通模版与组件:https://github.com/kissyteam/date-picker/blob/2622151aa29ef0c3f2b7d1c541b91699fe105298/lib/date-picker/xtpl/picker.xtpl#L59 66 | 67 | 对应组件方法:https://github.com/kissyteam/date-picker/blob/2622151aa29ef0c3f2b7d1c541b91699fe105298/lib/date-picker.js#L271 68 | 69 | 而 react 实际上没有模版的概念,通过 `jsx` 实现了一个 `虚拟 dom` ,jsx 可以利用全部的 js 特性,和组件沟通也更顺畅,例如 react calendar 主要渲染 “模版” 的地方: 70 | 71 | https://github.com/react-component/calendar/blob/a0d7d4e508ecbee676f56a60efa8b931df4aa098/lib/Calendar.js#L466 72 | 73 | 和组件沟通就顺畅很多: https://github.com/react-component/calendar/blob/a0d7d4e508ecbee676f56a60efa8b931df4aa098/lib/Calendar.js#L509 74 | 75 | https://github.com/react-component/calendar/blob/a0d7d4e508ecbee676f56a60efa8b931df4aa098/lib/Calendar.js#L247 76 | 77 | #### 局部刷新 78 | 79 | kissy 本质上是 `observer/pub/watcher` 模式, 当属性通过 `set` 方法发生改变,用户需要自行定义改变 dom 的代码来局部刷新:https://github.com/kissyteam/date-picker/blob/2622151aa29ef0c3f2b7d1c541b91699fe105298/lib/date-picker.js#L390 十分繁琐,并且大多使用 innerHTML 造成大量 gc 80 | 81 | 而 react 通过 `setState` ,`diff` , 以及 `批量更新` 机制,自动并高效得更新 dom,用户只需要关注 `render` 方法即可: https://github.com/react-component/calendar/blob/a0d7d4e508ecbee676f56a60efa8b931df4aa098/lib/Calendar.js#L40 82 | 83 | #### 生命周期 84 | 85 | react 和 kissy 都会有一些生命周期的 hook 函数可以定义,react 更加丰富 86 | 87 | ##### react : 88 | new hook: 89 | - getDefaultProps() 90 | - getInitialState() 91 | - componentWillMount() 92 | - render() 93 | - componentDidMount() 94 | - componentWillUnmount() 95 | 96 | update hook: 97 | - componentWillReceiveProps() 98 | - shouldComponentUpdate() 99 | - componentWillUpdate() 100 | - render() 101 | - componentDidUpdate() 102 | 103 | ##### kissy: 104 | new hook 105 | - initializer -> getInitialState 106 | - beforeCreateDom 107 | - afterCreateDom 108 | - beforeBindUI 109 | - afterBindUI 110 | - beforeRenderDom 111 | - afterRenderDom -> componentDidMount 112 | - destructor -> componentWillUnmount 113 | 114 | 常用的 react 都已经包含. 115 | 116 | #### 事件 117 | 118 | react 通过 `dom 事件全局代理` 以及模版内声明的方式达到了更少的原生事件注册,减少了内存占用,而 kissy 则是自动在组件跟节点进行绑定,如果需要内部节点事件则需要自行绑定 119 | 120 | kissy: https://github.com/kissyteam/date-picker/blob/2622151aa29ef0c3f2b7d1c541b91699fe105298/lib/date-picker.js#L238 121 | 122 | react: https://github.com/react-component/calendar/blob/a0d7d4e508ecbee676f56a60efa8b931df4aa098/lib/Calendar.js#L472 123 | 124 | 在组件方面 react 没有自定义事件的概念,也没有自定义事件的冒泡机制,组件事件实际上是通过 `callback` 传递来实现,不知道是优点还是缺点:https://github.com/react-component/menu/blob/45816af15fffb0c6e598602c289e39483fb1d6f7/lib/Menu.js#L162 125 | 126 | 而在 kissy 组件中 children 的自定义事件默认都会传递到 parent 上,触发 parent 的事件绑定,因此很容易就可以实现组件自定义事件的事件委托。 127 | 128 | 对于用户使用则无明显不同 129 | 130 | kissy: 131 | 132 | ```js 133 | var menu = new Menu({ 134 | listeners:{ 135 | “select”: function(){ 136 | } 137 | }, 138 | children:[{ 139 | new MenuItem() 140 | }] 141 | }).render(container); 142 | ``` 143 | 144 | react: 145 | 146 | ```js 147 | React.render() 148 | ``` 149 | 150 | #### 组件方法 151 | 152 | react 中由于 `render` 等都是虚拟 dom,取得组件实例需要通过在虚拟 dom 中配置 `ref` 属性:https://github.com/react-component/menu/blob/45816af15fffb0c6e598602c289e39483fb1d6f7/lib/Menu.js#L152 153 | 154 | 然后从组件的 `refs` map 中得到对应的组件实例后才能调用其方法:https://github.com/react-component/menu/blob/45816af15fffb0c6e598602c289e39483fb1d6f7/lib/Menu.js#L55 155 | 156 | 而 kissy 由于没有虚拟 dom 这一层,组件方法可以直接调用:https://github.com/kissyteam/menu/blob/af4d3628ff1bd4d262ffc944297af21ea8039cc4/lib/menu/control.js#L118 157 | 158 | 另外 react 不推荐组件的方法调用,推荐状态。而 kissy 若这么做,由于属性机制太弱,则得不偿失。 159 | 160 | ##### addChild/removeChild 161 | 162 | react 就是不需要了,只要渲染 child 的个数有变化, react 会自动对这次没有出现的 child component 进行销毁, 163 | 这里需要注意的是需要指定 child 的 key 属性,用来区分前后两次不同的 child component,这也是自动化所带来的代价。 164 | 165 | ```js 166 | React.render(12,container); 167 | // remove MenuItem 1, call componentWillUnmount of MenuItem 1 168 | React.render(2,container); 169 | ``` 170 | 171 | #### 大小对比 172 | 173 | react calendar (比 kissy date-picker 多了时间选择功能): rc-calendar/1.4.1/index-debug.js 41.5k 174 | 175 | kissy date-picker: http://g.tbcdn.cn/kissy/5/0.2.0/date-picker-debug.js+ 77.5k 176 | 177 | menu 奇迹发生了,大小竟然一样大: 178 | 179 | react menu: rc-menu/2.0.3/index-debug.js 23.3k 180 | 181 | kissy menu: http://g.tbcdn.cn/kissy/5/0.2.0/menu-debug.js 23.3k 182 | 183 | 184 | #### 生态圈/服务器端渲染 185 | 186 | kissy 生态圈为 gallery,一般只能客户端线上 cdn combo 使用。 187 | react 组件依托 npm,可以使用 npm 上的众多模块,配合 browserify/webpack 等工具可以完全离线开发,打包,并且可以在服务器端进行首屏渲染。 188 | 189 | #### 总结 190 | 191 | react 在吸收传统组件架构的基础上,通过自己的创新,大大提升了开发者的效率和使用体验,如果你仍然在用传统组件模式编码,我强烈建议你尽快切换到 react,人生苦短,活在当下 :) 192 | 而这篇文章我又多么希望一年前就有别人写给我看. 193 | 194 | -------------------------------------------------------------------------------- /tutorial/zh-cn/env/modulex-browserify-npm.md: -------------------------------------------------------------------------------- 1 | # npm-based front-end development using browserify and browser loader library 2 | 3 | 4 | `本文档已过时,请参考 [rc-server](http://github.com/react-component/rc-server) 以及本项目 [server](../../../server.js)` 5 | 6 | 原文: https://github.com/yiminghe/learning-react/blob/master/tutorial/env/modulex-browserify-npm.md 7 | 8 | 在基于浏览器的前端开发中,我们同样可以使用 npm 作为模块源.在这篇文章中我将介绍一种方法,通过该方法可以开发时在浏览器中通过一个浏览器端模块加载器(modulex)加载来自 npm 的模块,然后使用 browserify 打包后发布到线上使用. 9 | 之前你或许应该看下这篇文章: https://github.com/yiminghe/learning-react/blob/master/tutorial/zh-cn/env/setup-your-playground.md 10 | 11 | demo 在 https://github.com/yiminghe/learning-react/tree/master/example/react-router 12 | 13 | ## dependent tools 14 | 15 | * [nodejs](http://nodejs.org/) - server side javascript runtime 16 | * [modulex](https://github.com/kissyteam/modulex) - browser side loader library 17 | * [koa](https://github.com/koajs/koa) - a nodejs web framework 18 | * [koa-jsx](https://www.npmjs.org/package/koa-jsx) - koa middleware for transforming jsx of react 19 | * [koa-modularize](https://www.npmjs.org/package/koa-modularize) - koa middleware for transforming commonjs file into browser module format 20 | * [node-browserify](https://github.com/substack/node-browserify) - browser-side require() the node.js way 21 | * [bower](https://github.com/bower/bower) - A package manager for the web 22 | * [gulp](https://github.com/gulpjs/gulp) - The streaming build system 23 | * [react](https://www.npmjs.org/package/react) - ui library from facebook 24 | * [react-tools](https://www.npmjs.org/package/react-tools) - provide api to transform JSX into vanilla JS 25 | 26 | ## using modulex 27 | 28 | modulex 是一个浏览器端的模块加载器 29 | 30 | ### 创建 package.json 31 | 32 | For example: 33 | 34 | ```javascript 35 | { 36 | "name": "learning-react", 37 | "version": "1.0.0", 38 | "author": "yiminghe ", 39 | "engines": { 40 | "node": ">=0.11" 41 | }, 42 | "license": "MIT", 43 | "repository": { 44 | "type": "git", 45 | "url": "http://github.com/yiminghe/learning-react.git" 46 | }, 47 | "keywords": [ 48 | "react", 49 | "jsx", 50 | "koa" 51 | ], 52 | "devDependencies": { 53 | "gulp": "^3.8.10", 54 | "koa": "^0.13.0", 55 | "koa-jsx": "^1.0.0", 56 | "koa-modularize": "^1.0.0", 57 | "koa-mount": "^1.3.0", 58 | "koa-serve-index": "^1.0.1", 59 | "koa-static": "^1.4.7", 60 | "react": "^0.12.0", 61 | "react-router": "^0.10.2", 62 | "react-tools": "^0.12.0", 63 | "reactify": "~0.15.2" 64 | }, 65 | "scripts": { 66 | "start": "node --harmony server" 67 | } 68 | } 69 | 70 | ``` 71 | 72 | ### 创建 server.js 73 | 74 | For example: 75 | 76 | ```javascript 77 | var koa = require('koa'); 78 | var serve = require('koa-static'); 79 | var app = koa(); 80 | var path = require('path'); 81 | var cwd = __dirname; 82 | var serveIndex = require('koa-serve-index'); 83 | app.use(serveIndex(cwd, { 84 | hidden: true, 85 | view: 'details' 86 | })); 87 | var jsx = require('koa-jsx'); 88 | app.use(jsx(cwd, { 89 | reactTools: require('react-tools'), 90 | next:function(){ 91 | return 1; 92 | } 93 | })); 94 | var modularize = require('koa-modularize'); 95 | var mount=require('koa-mount'); 96 | app.use(mount('/example',modularize(path.resolve(cwd,'example')))); 97 | app.use(modularize()); 98 | app.use(serve(cwd, { 99 | hidden: true 100 | })); 101 | app.listen(8000); 102 | console.log('server start at ' + 8000); 103 | ``` 104 | 105 | 注意 ```app.use(modularize());``, 106 | 这句话将转化 commonjs 模块的代码为 modulex 可以在浏览器端加载的格式。 107 | 108 | 109 | ### 创建 application demo 110 | 111 | For example example/demo.html: 112 | 113 | ```html 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 129 | 130 | 131 | ``` 132 | 133 | And example/init.js 134 | 135 | ```javascript 136 | /** @jsx React.DOM */ 137 | 138 | var React = require('react'); 139 | var Router = require('react-router'); 140 | var Route = Router.Route; 141 | var Routes = Router.Routes; 142 | var Redirect = Router.Redirect; 143 | var Link = Router.Link; 144 | 145 | var App = React.createClass({ 146 | render: function() { 147 | return ( 148 |
149 |
    150 |
  • Bob
  • 151 |
  • Sally
  • 152 |
153 | 154 |
155 | ); 156 | } 157 | }); 158 | 159 | var User = React.createClass({ 160 | render: function() { 161 | return ( 162 |
163 |

User id: {this.props.params.userId}

164 |
    165 |
  • foo task
  • 166 |
  • bar task
  • 167 |
168 | 169 |
170 | ); 171 | } 172 | }); 173 | 174 | var Task = React.createClass({ 175 | render: function() { 176 | return ( 177 |
178 |

User id: {this.props.params.userId}

179 |

Task id: {this.props.params.taskId}

180 |
181 | ); 182 | } 183 | }); 184 | 185 | var routes = ( 186 | 187 | 188 | 189 | 190 | 191 | 192 | ); 193 | 194 | React.renderComponent( 195 | , 196 | document.body 197 | ); 198 | ``` 199 | 200 | 注意源码为 ``commonjs`` 格式 201 | 202 | ## run 203 | 204 | 先运行以下命令: 205 | ``` 206 | bower install modulex # install a browser loader library 207 | npm install # install npm modules 208 | npm start # start local server 209 | ``` 210 | 211 | 然后打开 [http://localhost:8000/example/demo.html](http://localhost:8000/example/demo.html) 即可. 212 | 213 | 214 | ## using browserify 215 | 216 | 添加 bundle 任务 217 | 218 | ```javascript 219 | var gulp = require('gulp'); 220 | var browserify = require('browserify'); 221 | var source = require('vinyl-source-stream'); 222 | gulp.task('bundle', function () { 223 | return browserify(['./init.js']) 224 | .transform(require('reactify')) 225 | .bundle() 226 | //Pass desired output filename to vinyl-source-stream 227 | .pipe(source('init.js')) 228 | // Start piping stream to tasks! 229 | .pipe(gulp.dest('../../example-bundle/react-router/')); 230 | }); 231 | ``` 232 | 233 | 创建 demo-bundle.html 并引入打包后的 javascript 234 | 235 | ```html 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | ``` 245 | 246 | ## run 247 | 248 | 先运行 ``gulp bundle`` ,然后打开 [http://localhost:8000/example/demo-bundle.html](http://localhost:8000/example/demo-bundle.html) 即可. 249 | 250 | ### 结束 251 | 252 | 恭喜,你现在可以通过浏览器端模块加载器快速开发,然后使用 browserify 打包后上线了。最重要是你可以很容易得共享前后端代码了。 -------------------------------------------------------------------------------- /tutorial/zh-cn/env/setup-project-env.md: -------------------------------------------------------------------------------- 1 | moved to https://github.com/yiminghe/koa-webpack-dev-test-server/blob/master/docs/zh-cn/how-to-setup-project-env.md -------------------------------------------------------------------------------- /tutorial/zh-cn/env/setup-your-playground.md: -------------------------------------------------------------------------------- 1 | 原文: https://github.com/yiminghe/learning-react/blob/master/tutorial/env/setup-your-playground.md 2 | 3 | 4 | 在本文我将介绍一种快速搭建 react demo 游乐场的方法。 5 | 6 | ## 依赖的工具 7 | 8 | * [nodejs](http://nodejs.org/) - server side javascript runtime 9 | * [koa](https://github.com/koajs/koa) - a nodejs web framework 10 | * [koa-jsx](https://www.npmjs.org/package/koa-jsx) - koa middleware for transforming jsx of react 11 | * [koa-modularize](https://www.npmjs.org/package/koa-modularize) - koa middleware for transforming commonjs file into browser module format 12 | * [react](https://www.npmjs.org/package/react) - ui library from facebook 13 | * [react-tools](https://www.npmjs.org/package/react-tools) - provide api to transform JSX into vanilla JS 14 | 15 | ## 初始化 package.json 16 | 17 | 在项目根目录创建 package.json 18 | 19 | ``` javascript 20 | { 21 | "name": "learning-react", 22 | "version": "1.0.0", 23 | "author": "yiminghe ", 24 | "engines": { 25 | "node": ">=0.11" 26 | }, 27 | "license": "MIT", 28 | "repository": { 29 | "type": "git", 30 | "url": "http://github.com/yiminghe/learning-react.git" 31 | }, 32 | "keywords": [ 33 | "react", 34 | "jsx", 35 | "koa" 36 | ], 37 | "devDependencies": { 38 | "koa": "^0.13.0", 39 | "koa-jsx": "^1.0.0", 40 | "koa-modularize": "^1.0.0", 41 | "koa-mount": "^1.3.0", 42 | "koa-serve-index": "^1.0.1", 43 | "koa-static": "^1.4.7", 44 | "react": "^0.12.0", 45 | "react-tools": "^0.12.0" 46 | }, 47 | "scripts": { 48 | "start": "node --harmony server" 49 | } 50 | } 51 | ``` 52 | 53 | 接着在根目录运行 ``npm install`` 命令 54 | 55 | ## 初始化 server.js 56 | 57 | 在项目根目录创建 server.js 58 | 59 | ```javascript 60 | var koa = require('koa'); 61 | var serve = require('koa-static'); 62 | var app = koa(); 63 | var path = require('path'); 64 | var cwd = __dirname; 65 | var serveIndex = require('koa-serve-index'); 66 | app.use(serveIndex(cwd, { 67 | hidden: true, 68 | view: 'details' 69 | })); 70 | var jsx = require('koa-jsx'); 71 | app.use(jsx(cwd, { 72 | reactTools: require('react-tools'), 73 | next:function(){ 74 | return 1; 75 | } 76 | })); 77 | var modularize = require('koa-modularize'); 78 | var mount=require('koa-mount'); 79 | app.use(mount('/example',modularize(path.resolve(cwd,'example')))); 80 | app.use(serve(cwd, { 81 | hidden: true 82 | })); 83 | app.listen(8000); 84 | console.log('server start at ' + 8000); 85 | ``` 86 | 87 | ## 开始 demo 代码 88 | 89 | 把你的 demo html and commonjs 格式的 javascript 文件放在 ``example`` 目录下. 90 | 91 | 92 | ### html file 93 | 例如: example/test.html 94 | 95 | ```html 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 111 | 112 | 113 | ``` 114 | 115 | ### js file 116 | 例如: example/hello.js 117 | 118 | ```javascript 119 | /** @jsx React.DOM */ 120 | 121 | module.exports = React.createClass({ 122 | render:function(){ 123 | return (
Hello React
); 124 | } 125 | }); 126 | ``` 127 | 128 | 例如: example/init.js 129 | 130 | ```javascript 131 | /** @jsx React.DOM */ 132 | 133 | var Hello = require('./hello'); 134 | 135 | React.render(,document.body); 136 | ``` 137 | 138 | 注意:第一行必须以 ``/** @jsx React.DOM */`` 开头 139 | 140 | ## 运行 demo 141 | 142 | 首先在项目根目录运行 ``npm start`` , 143 | 接着在浏览器中打开 [http://localhost:8000/example/test.html](http://localhost:8000/example/test.html). 144 | 145 | 恭喜! 你可以在浏览器上看到 ``Hello React``, 你可以修改 ``init.js`` 进行测试了! -------------------------------------------------------------------------------- /tutorial/zh-cn/meetings/react-europe-2015.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | react-europe 2015 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 32 | 33 | 36 | 37 | 42 | 43 | 44 | 45 | 46 |
47 | 48 |
49 |
50 |

ReactEurope 2015

51 | 52 |

53 | yiminghe@gmail.com 54 |

55 |
56 | 57 |
58 |

生态全景

59 | 60 |
    61 |
  • 数据
  • 62 |
  • 语言
  • 63 |
  • 打包
  • 64 |
  • 平台
  • 65 |
66 |
67 | 68 |
69 |

数据

70 | 71 |
    72 |
  • 松约束的 flux 类库以及进一步的函数式 redux
  • 73 |
  • 整合数据获取 relay(graphql)
  • 74 |
75 |
76 | 77 |
78 |

语言

79 | 80 |
    81 |
  • babel => jsx + es6
  • 82 |
  • 检测 eslint
  • 83 |
  • 类型系统 typescript/flow
  • 84 |
  • 底层编译 webassembly
  • 85 |
86 |
87 | 88 |
89 |

平台

90 | 91 |
    92 |
  • 浏览器: dom/svg/canvas
  • 93 |
94 |
    95 |
  • 原生平台: react-native android ios
  • 96 |
97 |
98 | 99 |
100 |
101 |

graphql

102 | 103 |

restful api 问题

104 | 105 |
    106 |
  • 每个 api 格式不一致
  • 107 |
  • 应用需求请求多次
  • 108 |
  • 版本号泛滥
  • 109 |
110 |
111 |
112 |

graphql 思路

113 |
    114 |
  • 解耦服务器端与客户端
  • 115 |
  • 本身不存储数据
  • 116 |
  • graphql 描述服务器提供的能力,客户端指定获取数据格式
  • 117 |
  • 服务器批量请求
  • 118 |
119 |
120 | 121 |
122 |

graphql 服务器端

123 | 124 |

一个类型定义

125 | 126 | 127 |
128 | 129 |
130 |

graphql 服务器端

131 | 132 |

如何数据获取

133 | 134 | 135 |
136 | 137 |
138 |

graphql 客户端

139 | 140 |

构建请求格式

141 | 142 |

143 | query NestedQuery {
144 |     hero {
145 |         name
146 |         friends {
147 |             name
148 |         }
149 |     }
150 | }
151 | 152 |

153 | hero: {
154 |     name: 'r2-d2',
155 |     friends: [{
156 |         name: 'f'
157 |     }]
158 | }
159 |                 
160 |
161 |
162 | 163 |
164 |

react-hot-loader

165 | 166 |

https://github.com/gaearon/react-hot-loader

167 | 168 |

基于 webpack 热加载特性,对组件类的原型方法(render)进行修改

169 | 170 |
    171 |
  • 不能热加载 store (有数据)
  • 172 |
  • redux: 无数据的 store, 可热加载
  • 173 |
174 |
175 | 176 |
177 |
178 |

redux

179 | 180 |

将数据保存在类库内部,通过函数回传给 store 处理函数

181 | 182 |

183 | export default function counter(state=0, action){
184 |     switch(action.type) {
185 |     // ...
186 |     // return state + 1;
187 |     }
188 | }
189 |                 
190 |
191 | 192 |
193 |

redux

194 | 195 |

组件通过 connector 声明需要的数据

196 | 197 |

198 | render(){
199 |     return <Connector select={
200 |                     (state) => {return {counter:state.counter}}
201 |                     }>
202 |     {
203 |     function({counter,dispatch}){
204 |         return <Counter counter={counter}/>
205 |     }
206 |     }
207 |     </Connector>
208 | }
209 |                 
210 |
211 |
212 | 213 |
214 |

inline style

215 | 216 |
    217 |
  • 整合 html/css/js 为一个可交互的完整组件,适合 webapp 类型
  • 218 |
  • 减少复杂度,无继承,优先级等问题
  • 219 |
  • 问题: 伪类,media query 等
  • 220 |
221 | 222 |

https://github.com/FormidableLabs/radium

223 |
224 | 225 |
226 |
227 |

relay

228 | 229 |

传统数据获取导致的问题

230 | 231 |
    232 |
  • 通用接口导致客户端的多次获取,效率低
  • 233 |
  • 特殊接口造成的维护难题
  • 234 |
  • 需求变动导致 underfetching/overfetching
  • 235 |
  • 最终导致客户端与服务器端耦合
  • 236 |
237 |
238 | 239 |
240 |

思考问题

241 | 242 | 243 |
244 | 245 |
246 |

relay

247 | 248 |

声明式的 api 消除逻辑错误,将数据获取和组件渲染放在一起

249 | 250 |

251 |                     ui = view(query(props))
252 |                 
253 |
254 | 255 |
256 |

relay code

257 | 258 |

259 | class Story extends React.Component {
260 |     render() {
261 |         var story = this.props.story;
262 |         return (
263 |             <View>
264 |             <Image uri={story.author.profile_picture.uri} />
265 |             <Text>{story.author.name}</Text>
266 |             <Text>{story.text}</Text>
267 |             </View>
268 |         );
269 |     }
270 | }
271 | module.exports = Relay.createContainer(Story, {
272 |     queries: {
273 |         story: graphql`
274 |             Story {
275 |                 author {
276 |                     name,
277 |                     profile_picture {
278 |                         uri
279 |                     }
280 |                 },
281 |                 text
282 |             }
283 |         `
284 |     }
285 | });
286 |                 
287 |
288 |
289 | 290 |
291 |
292 |

multiple targets

293 | 294 |

react 0.14-beta-1

295 | 296 |
    297 |
  • react & react-dom, dom 只是实现细节
  • 298 |
  • react 为组件规范,react-native/canvas 可共享 react 包
  • 299 |
300 | 301 |

302 | var React = require('react');
303 | var ReactDOM = require('react-dom');
304 | 
305 | var MyComponent = React.createClass({
306 |     render: function() {
307 |         return <div>Hello World</div>;
308 |     }
309 | });
310 | 
311 | ReactDOM.render(<MyComponent />, node);
312 |             
313 |
314 | 315 |
316 |

multiple targets

317 | 318 | 319 |
320 |
321 | 322 |
323 |
324 |

code transformation

325 | 326 |
    327 |
  • parser
  • 328 |
  • transformer
  • 329 |
  • generator
  • 330 |
331 |
332 | 333 |
334 |

parser

335 | 336 |

acorn, espree, esprima

337 | 338 |

string => ast

339 | 340 |
    341 |
  • lexical analysis
  • 342 |
  • syntactic analysis
  • 343 |
344 |
345 | 346 |
347 |

transformer

348 | 349 |

ast => ast

350 | 351 |
    352 |
  • traverse using visitor
  • 353 |
  • static analysis
  • 354 |
  • paths-based replacement
  • 355 |
356 |
357 | 358 |
359 |

generator

360 | 361 |

将转换后的 ast 序列化为字符串

362 | 363 |

escodegen

364 |
365 | 366 |
367 |

babel

368 | 369 |
    370 |
  • 扩展性的插件
  • 371 |
  • 可扩充语法
  • 372 |
373 |
374 |
375 | 376 |
377 |
378 |

animation in react

379 | 380 |

css transition 缺点

381 | 382 |
    383 |
  • 基于时间
  • 384 |
  • 不容易控制
  • 385 |
  • 依赖 DOM
  • 386 |
387 |
388 | 389 |
390 |

react-motion

391 | 392 |

393 |                     <Spring endValue={this.state.value}>
394 |                     {(value)=>{
395 |                     return <div style={{left:value}}></div>;
396 |                     }}
397 |                     </Spring>
398 |                 
399 |
400 | 401 |
402 |

react-motion

403 |
    404 |
  • 平台无关
  • 405 |
  • js 动画简单方便,不必关心时间
  • 406 |
  • 适合于一般任务
  • 407 |
  • 性能?
  • 408 |
409 |
410 |
411 | 412 |
413 |
414 |

react-router

415 | 416 | 417 |

将嵌套的 url 映射为 嵌套的组件

418 |
419 | 420 |
421 |

react-router

422 | 423 |

1.0.0-beta

424 | 425 |

支持 js 对象定义路由

426 | 427 |

428 | var rootRoute = {
429 |     component: App,
430 |     childRoutes: [
431 |         {
432 |             path: '/',
433 |             component: Index
434 |         },
435 |         {
436 |             path: 'state/:abbr',
437 |             component: State
438 |         },
439 |         {
440 |             path: '*',
441 |             component: Index
442 |         }
443 |     ]
444 | };
445 |                 
446 |
447 | 448 |
449 |

react-router

450 | 451 |

1.0.0-beta

452 | 453 |

支持异步路由

454 | 455 |

456 | module.exports = {
457 |     path: 'course/:courseId',
458 |     getChildRoutes (state, cb) {
459 |         require.ensure([], (require) => {
460 |             cb(null, [
461 |                 require('./routes/Announcements'),
462 |                 require('./routes/Assignments'),
463 |                 require('./routes/Grades'),
464 |             ])
465 |         })
466 |     },
467 |     getComponents (cb) {
468 |         require.ensure([], (require) => {
469 |             cb(null, require('./components/Course'))
470 |         })
471 |     }
472 | };
473 |                 
474 |
475 | 476 |
477 |

react-router

478 | 479 |

1.0.0-beta

480 | 481 |

参数,路由组件通过属性传递

482 | 483 |

484 |                     // components/App.js
485 |                     // state/ny
486 |                     render(){
487 |                     // this.props.children => state
488 |                     }
489 |                     // components/State.js
490 |                     render() {
491 |                     // this.props.params.abbr => ny
492 |                     }
493 |                 
494 |
495 |
496 | 497 |
498 |

going mobile with react

499 | 500 |

https://github.com/touchstonejs/touchstonejs

501 | 502 |
    503 |
  • navigation
  • 504 | 505 |
  • form
  • 506 | 507 |
  • control
  • 508 |
509 |
510 | 511 |
512 | 513 |
514 |
515 |
516 | 517 | 518 | 519 | 559 | 560 | 561 | 562 | -------------------------------------------------------------------------------- /tutorial/zh-cn/practice/checkbox.md: -------------------------------------------------------------------------------- 1 | ## 一步步实现多选框 2 | 3 | ### 定义 4 | 5 | 多选框,英文 checkbox,浏览器原生提供的组件为 ``,实际应用中由于设计的主题风格不同,一般都不使用系统自带的组件而是由开发者实现. 6 | 7 | 8 | ### 分析功能 9 | 10 | 多选框主要的功能是可以实现并记忆选中状态并通知通知,支持的设备包括鼠标,键盘,触摸屏等。 11 | 12 | 13 | ### react 实现 14 | 15 | #### api 设计 16 | 17 | react 的 api 一般只是属性,属性可以分为数据属性和回调函数,对应于这个组件来说,应该包括 checked(当前是否选中),defaultChecked(初始是否选中)以及回调 onChange 函数. 18 | 关于为什么区分 checked 和 defaultChecked 属性,可详细阅读 http://reactjs.cn/react/docs/forms.html 中的受限组件部分。 19 | 20 | #### 使用例子 21 | 22 | 先把使用的例子写出来,后面一步步实现功能即可 23 | 24 | ```html 25 | 26 |
27 | 50 | ``` 51 | 52 | 例子中包含两个组件实例: 53 | 54 | 第一个为受限组件 55 | 56 | ```html 57 | 58 | ``` 59 | 60 | 用户点击无法切换选中与非选中状态,这个组件的选中与非选中状态由属性控制。 61 | 62 | 第二个为非受限组件 63 | 64 | ```html 65 |

66 | ``` 67 | 68 | 只设定了初始值,用户之后可以通过点击切换选中与非选中状态,并且通过 onChange 属性设定回调函数,当组件状态改变后,再根据这个组件的状态设置上面受限组件的状态。 69 | 70 | #### 属性的默认初始值 71 | 72 | checked 为受限属性所以不能设置默认值,多选框一般默认为不选中,所以 defaultChecked 为 false,同时设置 onChange 为空函数避免以后的频繁检测。 73 | 根据以上分析实现组件的 getDefaultProps 方法: 74 | 75 | ```js 76 | var Checkbox = React.createClass({ 77 | getDefaultProps() { 78 | return { 79 | defaultChecked: false, 80 | onChange(){} 81 | }; 82 | } 83 | }); 84 | ``` 85 | 86 | 87 | #### 状态分析 88 | 89 | checkbox 只有一个状态,表示该组件的选中与否,并且这个状态的初始值有两种方式来设定,如果当前组件指定了 checked 的属性,那么初始状态就取 checked 的属性值,否则就取 defaultChecked 的属性值. 根据以上分析实现组件的 getInitialState 方法 90 | 91 | ```js 92 | var Checkbox = React.createClass({ 93 | getDefaultProps() { 94 | return { 95 | defaultChecked: false, 96 | onChange(){} 97 | }; 98 | }, 99 | 100 | getInitialState() { 101 | var state = {}; 102 | var props = this.props; 103 | if('checked' in props){ 104 | state.checked = props.checked; 105 | } else { 106 | state.checked = props.defaultChecked; 107 | } 108 | return state; 109 | } 110 | }); 111 | ``` 112 | 113 | #### 界面描述 114 | 115 | 接着根据组件的状态描述组件的界面,这里就简单点处理,如果组件为选中状态则为背景色红,否则无背景色. 根据以上描述实现 render 方法: 116 | 117 | ```js 118 | var Checkbox = React.createClass({ 119 | getDefaultProps() { 120 | return { 121 | defaultChecked: false, 122 | onChange(){} 123 | }; 124 | }, 125 | 126 | getInitialState() { 127 | var state = {}; 128 | var props = this.props; 129 | if('checked' in props){ 130 | state.checked = props.checked; 131 | } else { 132 | state.checked = props.defaultChecked; 133 | } 134 | return state; 135 | }, 136 | 137 | render() { 138 | var state = this.state; 139 | var style = {border:'1px solid red',display:'inline-block',width:100,height:100} 140 | if(state.checked){ 141 | style.backgroundColor='red'; 142 | } 143 | return ; 144 | } 145 | }); 146 | ``` 147 | 148 | #### 绑定事件 149 | 150 | 接下来处理组件的交互问题,需要绑定 dom 事件,然后根据组件是否受限来改变组件的状态,最后调用回调函数通知外部用户即可,这里演示下 click 事件,键盘事件同理(需格外设置 dom 的 tabIndex 属性) 151 | 152 | 153 | ```js 154 | var Checkbox = React.createClass({ 155 | getDefaultProps() { 156 | return { 157 | defaultChecked: false, 158 | onChange(){} 159 | }; 160 | }, 161 | 162 | getInitialState() { 163 | var state = {}; 164 | var props = this.props; 165 | if('checked' in props){ 166 | state.checked = props.checked; 167 | } else { 168 | state.checked = props.defaultChecked; 169 | } 170 | return state; 171 | }, 172 | 173 | onClick() { 174 | var nextChecked = !this.state.checked; 175 | if(!('checked' in this.props)){ 176 | // 非受限 177 | this.setState({ 178 | checked: nextChecked 179 | }); 180 | } 181 | // 回调函数通知外部 182 | this.props.onChange(nextChecked); 183 | }, 184 | 185 | render() { 186 | var state = this.state; 187 | var style = {border:'1px solid red',display:'inline-block',width:100,height:100} 188 | if(state.checked){ 189 | style.backgroundColor='red'; 190 | } 191 | return ; 192 | } 193 | }); 194 | ``` 195 | 196 | #### 还没有完 197 | 198 | 现在并没结束,我们知道在受限模式下,用户只能通过重新渲染来改变组件的属性进而改变组件的 ui 展示,那么当用户改变组件的属性后我们需要同步到组件的对应状态, 199 | 从而 render 根据状态来渲染 ui. react 中是通过定义 componentWillReceiveProps 来同步属性的更改到 状态,实现如下: 200 | 201 | ```js 202 | var Checkbox = React.createClass({ 203 | getDefaultProps() { 204 | return { 205 | defaultChecked: false, 206 | onChange(){} 207 | }; 208 | }, 209 | 210 | getInitialState() { 211 | var state = {}; 212 | var props = this.props; 213 | if('checked' in props){ 214 | state.checked = props.checked; 215 | } else { 216 | state.checked = props.defaultChecked; 217 | } 218 | return state; 219 | }, 220 | 221 | componentWillReceiveProps(newProps){ 222 | // 组件重新渲染了,属性可能有改变,同步属性到状态 223 | if('checked' in newProps){ 224 | this.setState({ 225 | checked: newProps.checked 226 | }); 227 | } 228 | }, 229 | 230 | onClick() { 231 | var nextChecked = !this.state.checked; 232 | if(!('checked' in this.props)){ 233 | // 非受限 234 | this.setState({ 235 | checked: nextChecked 236 | }); 237 | } 238 | // 回调函数通知外部 239 | this.props.onChange(nextChecked); 240 | }, 241 | 242 | render() { 243 | var state = this.state; 244 | var style = {border:'1px solid red',display:'inline-block',width:100,height:100} 245 | if(state.checked){ 246 | style.backgroundColor='red'; 247 | } 248 | return ; 249 | } 250 | }); 251 | ``` 252 | 253 | ### 结束 254 | 255 | 这样一个简单的组件就完成,当然优化和功能是永无止境的,比如如何实现只读功能, 256 | 如何配合原生的 dom label 标签等,有兴趣的可研究 [rc-checkbox](https://github.com/react-component/checkbox) 项目 -------------------------------------------------------------------------------- /tutorial/zh-cn/practice/tb-app.md: -------------------------------------------------------------------------------- 1 | ## react 高级教程练习作业 2 | 3 | 使用 [react-router@beta](https://github.com/rackt/react-router), 4 | [antd select](http://ant.design/components/select/), 5 | [antd table](http://ant.design/components/table/) 做一个类似淘宝的带搜索和列表页的应用. 6 | 7 | ### 示例截图 8 | 9 | 搜索: 10 | 11 | ![](http://gtms04.alicdn.com/tps/i4/TB13LcZJpXXXXb1XXXXaNQJJVXX-676-433.png) 12 | 13 | 列表: 14 | 15 | ![](http://gtms04.alicdn.com/tps/i4/TB1KnsIJpXXXXcbXFXXXNRGFVXX-666-571.png) 16 | 17 | ![](http://gtms02.alicdn.com/tps/i2/TB1NcssJpXXXXajaXXXzdh.8FXX-656-503.png) --------------------------------------------------------------------------------