https://facebook.github.io/react/contributing/codebase-overview.html
- FacebookではHasteというモジュールシステムを使っている
- all filenames are globally unique
require('../foo/bar')
の代わりにrequire('bar')
とする- ファイル移動しても壊れない
- Fuzzy Finder使いやすい
- ビルド時に、全てのファイルを
/lib
下にフラットに配置するrequire
の引数に./
を追加する- 結果、CommonJSで解釈できるようになる
- fbjs に依存してるよ
src
: 本体docs
: https://facebook.github.io/react のソースコードexamples
packages
: npmパッケージのメタデータ置き場 (package.json 等)。ソースコードはsrc
にあるbuild
: ビルド済みファイル置き場
- テストファイルはテストしたいファイルのすぐ近くにある
- 例)
src/addons/update.js
のテストはsrc/addons/__tests__/update-test.js
- 例)
- 基本的に、同じディレクトリ or 子ディレクトリのファイルのみimportする
- 循環参照を避けるための規約
- 2つのディレクトリで共有したいコードがある場合、共通の親ディレクトリに
shared
を作って、そこに置く
- fbjsのwarning, invariantをよく使う
- warning: 第一引数がfalseの時、警告する
- developmentでのみ有効
- 警告の嵐をさけるため、警告と同時にフラグを立てることがよくある
- invariant: 第一引数がfalseの時、エラーを吐いて死ぬ
- productionでも有効
- productionのときはエラーメッセージじゃなくてエラーコードが出る(ファイルサイズ削減のため)
global.__DEV__
は process.env.NODE_ENV !== 'production'
の代わりに使える
- 昔のコードで使ってた。型チェックはしてない
- 新しいコードではflowtypeを使ってる
- 型つけるPullReqは絶賛受付中!
殆どのコードはまだES5で書かれてる
// Constructor
function ReactDOMComponent(element) {
this._currentElement = element;
}
// Methods
ReactDOMComponent.Mixin = {
mountComponent: function() {
// ...
}
};
// Put methods on the prototype
Object.assign(
ReactDOMComponent.prototype,
ReactDOMComponent.Mixin
);
module.exports = ReactDOMComponent;
- ここでいう Mixin は React の
mixins
とは無関係- 他のクラスにMixinするのに便利で使ってた
- ES6 Classに書き直したりもするけど、優先度は低い
- React Fiber で、あまり OOP っぽくないコードに置き換わる見込み
- DOMやReactNativeなど、環境による違いを吸収するため、実行時に依存クラスをinjectしてるコードがある
// Dynamically injected
var textComponentClass = null;
// Relies on dynamically injected value
function createInstanceForText(text) {
return new textComponentClass(text);
}
var ReactHostComponent = {
createInstanceForText,
// Provides an opportunity for dynamic injection
injection: {
injectTextComponentClass: function(componentClass) {
textComponentClass = componentClass;
},
},
};
module.exports = ReactHostComponent;
この例だと、次のようにinjectされる
- DOM:
ReactHostComponent.injection.injectTextComponentClass(ReactDOMTextComponent);
- ReactNative:
ReactHostComponent.injection.injectTextComponentClass(ReactNativeTextComponent);
将来Dynamic Injectionやめてビルド時に良い感じにしたいけど、まだできてない
- Reactはmonorepo
- 複数のnpmパッケージを1つのgitレポジトリで管理
- ref. lerna
- 以下のAPIだけ提供する
- React.createElement()
- React.createClass()
- React.Component
- React.Children
- React.PropTypes
- reconciliation や環境依存のコードはない
- v15.4.0 で react.js から react-dom のコードが削除された
- 3種類のrenderers
- React DOM Renderer: https://npm.im/react-dom
- react-dom.js に相当
- React Native Renderer: https://npm.im/react-native-renderer
- 将来 ReactNative のレポジトリに移動するかも
- React Test Renderer: https://npm.im/react-test-renderer
- JSONを出力する。Jest用
- React DOM Renderer: https://npm.im/react-dom
react-artというのも一応公式rendererなので、reactのリポジトリに組み込まれている
- 環境に依存しない reconciliation 処理をおこなう
- render を呼んだり、lifecycle methodsを呼んだり、refsを管理したり
- no pubic APIs
- rendererから呼ばれる
- "internal tree" とReactコンポーネントを管理する
- internal instance は composite と host の2種類がある
- internal instance は外部からは触れない
- プラットフォーム毎に提供されるもの
<div>
や<View>
など
ReactDOMComponent
, ``- mounting, updates, unmounting を行う
- ユーザー定義のもの
ReactCompositeComponent
- mounting, updates, unmounting を行う
- update時の処理
- 新しい render() 結果の type, key を調べる
- 変化がない場合: 子供の render() を呼ぶ
- 変化がある場合: 子供を unmount して新しいのを mount
- renderは再帰的に行われる
- シングルパス、同期的
- reconciler書き直し計画
- 目的
ー 処理をチャンクに分割して割り込みできるようにする
ー チャンクに優先度つけて、一時停止とかできるように
ー 親子間を行ったり来たりして処理できるようにする、レイアウトを考慮して処理する
ー
render()
で複数の要素を返せるようにする ー エラー境界?のより良いサポート
詳細: https://github.com/acdlite/react-fiber-architecture
- React は生のDOMイベントではなく、自前で実装した synthetic event を利用する
- renderer 非依存
- TransitionGroup, CSSTransitionGroup: アニメーションとか
- src/addons/transitions
- createFragment: 子コンポーネントの配列にkeyを設定しづらいときに使う
- src/addons/ReactFragment.js
- Perf: パフォーマンス計測用
- src/renderers/shared/ReactPerf.js
- ReactTestUtils: テスト用
- src/test/ReactTestUtils.js