ReScript in Korean

JSX

원문

리스크립트로 HTML 구문을 작성할 것 같으신가요? 아니라면 이 섹션은 그냥 넘어가셔도 됩니다.

리스크립트는 JSX 문법을 지원하지만 ReactJS에 있는 것과 조금 다릅니다. 리스크립트 JSX는 ReactJS와 관련이 없습니다. 일반 함수 호출로 변환되기 때문입니다.

참고 ReasonReact 를 사용하시는 분들에게: ReasonReact가 JSX를 변화시키는 것은 아닙니다. 자세한 내용은 사용 섹션을 참고하세요.

대문자 태그

<MyComponent name={"ReScript"} />
React.createElement(MyComponent.make, MyComponent.makeProps('ReScript', undefined));

이렇게 변경됩니다.

@JSX MyComponent.createElement(~name="ReScript", ~children=list{}, ())
React.createElement(MyComponent.make, MyComponent.makeProps('ReScript', undefined));

소문자 태그

<div onClick={handler}> child1 child2 </div>
React.createElement(
'div',
{
onClick: handler,
},
child1,
child2
);

이렇게 되고요

@JSX div(~onClick=handler, ~children=list{child1, child2}, ())
React.createElement(
'div',
{
onClick: handler,
},
child1,
child2
);

Fragment

<> child1 child2 </>
React.createElement(React.Fragment, undefined, child1, child2);

리액트 Fragment는 이렇게 변경됩니다.

@JSX list{child1, child2}
React.createElement(React.Fragment, undefined, child1, child2);

Children

<MyComponent> child1 child2 </MyComponent>
React.createElement(MyComponent.make, MyComponent.makeProps(null, undefined), child1, child2);

이것은 child1child2 두 아이템을 children 위치로 전달하는 문법입니다. 문법적 설탕이 제거 된 child1child2을 포함한 리스트 문법입니다.

@JSX MyComponent.createElement(~children=list{child1, child2}, ())
React.createElement(MyComponent.make, MyComponent.makeProps(null, undefined), child1, child2);

참고 이것은 ReasonReact의 변환은 아닙니다. ReasonReact는 최종에는 리스트를 배열로 바꿉니다. 이 아이디어는 여전히 유효합니다.

따라서 자연스럽게, <MyComponent> myChild </MyComponent>@JSX MyComponent.createElement(~children=list{myChild}, ()) 이 문법으로 변경됩니다. 무엇을 하든 childre에 전달된 인수는 리스트로 감싸집니다. 만일 그렇게 전달되기 원하지 않는다면? 추가적인 래핑 없이 myChild를 직접 전달하려면 어떻게 해야할까요?

Children Spread

위 문제를 해결하기 위해 우리는 이런 방식을 제안합니다.

<MyComponent> ...myChild </MyComponent>
React.createElement(MyComponent.make, MyComponent.makeProps(myChild, undefined));

이 방법은 myChild를 리스트로 감싸지 않고 인자로 넘길 수 있습니다. (ReasonReact의 경우에는 배열) 위에서 말했듯 이렇게 변경됩니다.

@JSX MyComponent.createElement(~children=myChild, ())
React.createElement(MyComponent.make, MyComponent.makeProps(myChild, undefined));

This is extra useful in the cases where you are handled myChild that is already a list of things, and want to forward that without wrapping it an extra time (타입 오류가 될 수 있습니다.) *. 또한 children 위치에서 임의의 자료구조를 전달할 수 있습니다. (기억하세요 JSX children 은 완전히 일반적인 prop 입니다.):

<MyComponent> ...((theClassName) => <div className=theClassName />) </MyComponent>
<MyForm> ...("Hello", "Submit") </MyForm>
React.createElement(
make,
makeProps(function(theClassName) {
return React.createElement('div', {
className: theClassName,
});
}, undefined)
);
React.createElement(MyForm.make, MyForm.makeProps(['Hello', 'Submit'], undefined));

사용법

ReasonReact JSX 문서를 보시면 위의 호출을 특별한 ReasonReact 호출로 변경하는 JSX 어플리케이션 예제가 있습니다.

여기 JSX 태그의 대부분의 기능을 보여주는 예제가 있습니다.

<MyComponent
booleanAttribute={true}
stringAttribute="string"
intAttribute=1
forcedOptional=?{Some("hello")}
onClick={handleClick}>
<div> {React.string("hello")} </div>
</MyComponent>
React.createElement(
MyComponent.make,
MyComponent.makeProps(
true,
'string',
1,
'hello',
handleClick,
React.createElement('div', undefined, 'hello'),
undefined
)
);

JS, JSX 에서의 다른점

  • 속성과 children은 늘 {}를 필요로 하는 것은 아닙니다만, 학습의 용이성을 위해 보여주고 있습니다. 아마 포매팅을 하시면, 어떤 괄호는 사라지고, 어떤 부분은 괄호로 변경될 것입니다.
  • JSX Props spread 구문은 지원하지 않습니다. <Comp {...props} />. 우리가 위에 설명한 children spread 기능이 있는것과 조금 관련이 있습니다. <Comp> ...children </Comp>.
  • 약어!

약어 (Punning)

약어는 Props 명칭과 값이 같을 때 사용할 수 있는 줄임말입니다. 예를 들어, 자바스크립트에서는, return {name: name} 이렇게도 할 수 있지만 이런 식으로 사용합니다. return {name}.

리즌 JSX는 약어를 지원합니다. <input checked /> 는 단순히 이런 표현의 줄임입니다. <input checked=checked />. 포매터가 작동할 때마다 약어처리가 가능한 곳이 자동으로 변경될 것입니다. 약어 처리는 전달해야하는 Props 가 많을 경우 편리합니다.

<MyComponent isLoading text onClick />
React.createElement(MyComponent.make, MyComponent.makeProps(isLoading, text, onClick, undefined));

결과적으로 리즌 JSX 컴포넌트는 Props 주입을 막는 추가적인 라이브러리에 도달하기 전에 임의적으로 몇가지 Props 를 더 주입할 수 있습니다.

참고 그것은 ReactJS JSX로부터 출발한 것이며, 여기에는 약어가 없습니다. ReactJS의 <input checked />는 이전 버전과의 호환성을 위해 DOM 관용구를 따르기 때문에 <input checked=true />로 변경 됩니다.

팁과 트릭

JSX 의 장점을 활용하는 라이브러리 작성자들에게 @JSX는 JSX 포매팅하려는 함수를 찾는 잠재적인 ppx 매크로입니다. 이 기능을 찾아서 여러분은 이것을 다른 표현으로 바꿀 수 있습니다.

이 방법은, 모든사람이 특정 라이브러리(ReasonReact)를 사용할 필요없이 JSX 문법의 이득을 얻을 수 있습니다.

JSX calls supports the features of labeled functions: optional, explicitly passed optional and optional with default. JSX 호출은 이름있는 인자 기능을 지원합니다. 명시적으로 옵셔널 값을 전달할 수 있고 기본은 옵셔널입니다.

디자인 결정

* 여러분은 아마 왜 children spread 같은 방법이 ReactJS에서 필요하지 않은지 궁금할 것입니다. ReactJS는 일부 특수한 런타임 로직과 특수 구문 변환 그리고 가변 인수 감지 마킹을 사용해 이런 경우를 대부분 방지합니다.(이곳을 참조해주세요). 이런 동적 사용은 타입 시스템 감지를 조금 복잡하게 만듭니다. 우리가 ReasonReact의 모든 구문을 컨트롤하기 때문에 컴파일 시간 및 런타임 필요없이 래핑하거나 래핑하지 않는 경우를 명확히 구분하기위해 children spread를 사용하기로 결정했습니다!