Slide 1

Slide 1 text

Fast JSX: Don't clone props object #28768 @yossydev 1

Slide 2

Slide 2 text

Profile Name: ユウト Field: Web Developer Blog: yossy.dev SNS / Youtube: @yossydev 2

Slide 3

Slide 3 text

Agenda 1. 高速化のポイント 2. key, ref の予約語をprops からの削除 3. public api であるcreateElement 後のprops の上書き 4. 実装を見る 3

Slide 4

Slide 4 text

高速化のポイント 4

Slide 5

Slide 5 text

高速化のポイント props をクローンする必要がなくなった 5

Slide 6

Slide 6 text

高速化の要因 props をクローンする必要がなくなった ではなぜprops をクローンする必要があったのか 1. key, ref の予約語をprops からの削除 2. public api であるcreateElement 後のprops の上書き 6

Slide 7

Slide 7 text

1. key, ref の予約語をprops から削除すること 7

Slide 8

Slide 8 text

1. key, ref の予約語をprops から削除すること: key とref key: リスト内の要素を一意に識別するためのプロパティ ref: コンポーネントのdom 動作を行うことができるプロパティ // key const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((number) => (
  • {number}
  • )); // ref const FancyButton = React.forwardRef((props, ref) => ( {props.children} )); 8

    Slide 9

    Slide 9 text

    1. key, ref の予約語をprops から削除すること 問題点 key とref をprops で渡さないようにする必要があった。 for (propName in config) { if ( hasOwnProperty.call(config, propName) && propName !== 'key' && (enableRefAsProp || propName !== 'ref') ) { if (enableRefAsProp && !disableStringRefs && propName === 'ref') { props.ref = coerceStringRef( config[propName], ReactCurrentOwner.current, type, ); } else { props[propName] = config[propName]; 9

    Slide 10

    Slide 10 text

    1. key, ref の予約語をprops から削除すること 解消方法 React19 からは props.ref でref にアクセスできるようになるそう 今までは React.forwardRef で囲む必要があった このアップデートによりref の問題は解消できた そしてkey も元々スプレット構文を使わなければクローンはされないようになって いました。 スプレット構文を使わなければjsx 関数の第三匹数に値が入る key の解決 (スプレット構文使用時以外) 10

    Slide 11

    Slide 11 text

    2. createElement がpublic api である 11

    Slide 12

    Slide 12 text

    2. createElement がpublic api である createElement とは何か React17 以前で使われていたjsx をdom に変換するための関数。これは我々開発者が React からimport して使用することもできる // jsx // compiled jsx function Greeting({ name }) { function Greeting({ name }) { return ( return createElement(

    "h1", Hello {name}. Welcome! { className: "greeting" },

    "Hello ", ); createElement("i", null, name), } ". Welcome!", ); } 12

    Slide 13

    Slide 13 text

    2. createElement がpublic api である ユーザーによるprops の上書き ユーザーがprops の上書きができてしまうので、予期しないバグが起きる恐れがある。 const props = { className: "my-div" }; const element2 = React.createElement("div", props); props.className = "my-div-changed"; console.log(element2.props.className); // 'my-div-changed' 13

    Slide 14

    Slide 14 text

    2. createElement がpublic api である React17 以降 createElement ではなくjsx 関数が使われるようになった。(React17 におけるJSX の新し い変換を理解する) // jsx // compiled jsx function Greeting({ name }) { function Greeting({ name }) { return ( return _jsxs("h1", {

    className: "greeting", Hello {name}. Welcome! children: ["Hello ", _jsx("i", { children: name }), ". Welcome!"]

    }); ); } } 14

    Slide 15

    Slide 15 text

    2. createElement がpublic api である the new JSX runtime, jsx, is not a public API 翻訳: 新しいJSX ランタイムjsx はパブリックAPI ではない jsx 関数はpublic api ではないため、ユーザーによるprops の上書きを考慮する必要がな くなった 15

    Slide 16

    Slide 16 text

    2. createElement がpublic api である 疑問点: the new JSX runtime, jsx, is not a public API react/jsx-runtime からimport して使えるやーーん import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const Foo = () => { return _jsxs( "div", { children: [ _jsx("p", { id: "a", children: "I am foo" }, void 0), _jsx("p", { children: "I am foo2" }, "b"), ], }, void 0, ); }; 16

    Slide 17

    Slide 17 text

    2. createElement がpublic api である 予想: the new JSX runtime, jsx, is not a public API jsx のコメントを見た感じは、使えないではなく使ってもこっちは知らないよみたいな ニュアンスなのかなと感じています。 /** * Create a React element. * * You should not use this function directly. Use JSX and a transpiler instead. */ export function jsx( type: React.ElementType, props: unknown, key?: React.Key, ): React.ReactElement; 17

    Slide 18

    Slide 18 text

    実装を見てみる 18

    Slide 19

    Slide 19 text

    実装を見てみる 単純にfor 分で回さなくてよくなったので早くなってそう... ?? // Before: config をfor 分で回して条件に一致したconfig だけkey で抽出してprops のkey に代入している for (propName in config) { if ( ... ) { if (enableRefAsProp && !disableStringRefs && propName === 'ref') { ... } else { props[propName] = config[propName]; // After: config を直接props に代入してReactElement に渡している let props; if (enableRefAsProp && disableStringRefs && !('key' in config)) { props = config; 19

    Slide 20

    Slide 20 text

    まとめ 今まではprops をクローンする必要があった 1. key, ref の予約語をprops から削除すること ref はprops で参照できるようになる、key もスプレット構文を使わなければ問題なし! 2. createElemet 後にprops の上書き React17 からjsx という関数が使われていて、それは我々開発者が使うことを推奨して いないようなので気にしないでヨシッ ! 実装 今までfor...in でぐるぐる回していたところを単純にfor 分で回さなくてよくなった 20

    Slide 21

    Slide 21 text

    Have a good development life! 21