생산 응용의 이유는?🤔 (섹션 4)
26616 단어 reactreasonjavascript
하지만 자네도 ReasonML을 평가하고 있다면 내 의견은 중요하지 않을 거야.이것이 바로 제가 생산 과정에서 어떤 것을 사용할지 결정하는 데 도움을 줄 수 있는 방법을 공유하는 이유입니다.
이 시리즈를 만들 때 배운 다섯 가지 기교도 볼 수 있는데, 이것들은ReasonReact를 사용하여 프로그램을 구축할 때 매우 유용하다.
유형 덮어쓰기 및 개발 속도
유형 덮어쓰기
컴파일할 때 우리의 코드를 더욱 신뢰할 수 있도록 양호한 형식 커버율을 확보하는 것이 중요하다.프로그램의 행동이 우리가 예상한 것과 같지 않으면 오류가 발생할 수 있습니다.형식 덮어쓰기는 '코드를 컴파일할 때' (당신이 그것을 실현할 때), 이러한 행위를 명확하게 설명하도록 합니다.맞아요. 모든 버그가 유형과 관련이 있는 것은 아닙니다.그러나 입력 값에 대한 정의가 명확할수록 버그 검사 작업을 컴파일러 자체에 의뢰할 수 있습니다.
정적 입력 코드의 부작용 중 하나는 코드의 가독성을 높이는 것이다.코드 편집기와 문법 플러그인은 컴파일러가 제공하는 정적 형식 정보를 사용할 수 있으며, 읽는 코드에 대한 힌트를 제공합니다.코드 라이브러리가 클수록, 너는 그것을 더욱 좋아한다.
발전 속도
우리의 납품 기능의 속도는 절대로 우리의 효율을 평가하는 기준이므로 소홀히 해서는 안 된다.어떤 경우에, 이것은 심지어 가장 중요한 일이다.
개발 속도도 매우 중요하다. 왜냐하면 그것은 개발자의 체험에서 중요한 요소이기 때문이다.도구가 어떤 것들을 신속하게 실현하는 것을 쉬워지게 할 때, 사람들은 종종 그것을 사용하기 쉽고, 채택되기 쉽다.단지 우리들 대부분이 우리가 세운 결과를 좋아하고 가능한 한 빨리 이 결과를 얻기를 원하기 때문이다.
그럼, 어떻게 결정합니까?
매일 사용해야 할 도구를 선택하여 물건을 구축할 때, 유형 범위와 개발 속도를 고려하는 것이 중요하다.
이상적인 상황에서 우리는 다음과 같은 것이 있을 것이다.
유형 덮어쓰기 범위:██████████ 100%
발전 속도:██████████ 100%
불행히도 이것은 비현실적이다.
JavaScript는 개발 속도에 놀라움을 자아냅니다.이 언어는 매우 동적이며 몇 줄의 코드만 있으면 신속하게 실현할 수 있다.
다음은 단일 행 직렬 함수입니다.
let concat = (a, b) => a + b;
// concatenate strings
concat("Hello ", "World"); // output: "Hello World"
// concatenate strings with numbers
concat("hello", 3); // output: "Hello 3
그러나 JavaScript는 정적 유형 덮어쓰기에 따른 예측 가능성 및 가독성 이점을 제공하지 않습니다.
나의 판결
저는 처음부터 ReasonML이 분명히 있을 거라는 걸 알았어요.💯 유형 덮어쓰기에서 득점하다.
하지만 과거 도서관에서 겪은 경험은 개발 속도에 대해 의심스럽다.이 점은 다음과 같은 도전에 직면했을 때 증명되었다.
let concat = (a, b) => a + b;
// concatenate strings
concat("Hello ", "World"); // output: "Hello World"
// concatenate strings with numbers
concat("hello", 3); // output: "Hello 3
이것은 아주 좋습니다. 리액션 프로그램을 구축하는 도구가 있기 때문에, 개발 속도에 영향을 주지 않고 매우 강력한 범위를 제공할 수 있습니다.
다음 시간에 저는 리슨 커뮤니티가 이런 문제들을 해결하기 위해 제공하는 기교를 소개할 것입니다.
추리 기교
팁 1: 컨텍스트에서 반응
React 컨텍스트를 작성하고 사용하려면 컨텍스트 제공 프로그램을 사용자 정의 어셈블리로 포장해야 합니다.
/* MyContextProvider.re */
let context = React.createContext(() => ());
let makeProps = (~value, ~children, ()) => {
"value": value,
"children": children,
};
let make = React.Context.provider(context);
그런 다음 작성된 컨텍스트 제공 프로그램을 사용하여 다음과 같이 작업을 수행할 수 있습니다.
[@react.component]
let make = (~children) => {
<MyContextProvider value="foo">
children
</MyContextProvider>
}
module ChildConsumer = {
[@react.component]
let make = (~children) => {
let contextValue = React.useContext(MyContextProvider.context);
};
팁 2: CSS 필요
BuckleScript는 유형 보안에 영향을 주지 않으면서 JavaScript 모듈이 필요한 방법을 제공합니다.그러나 CSS 파일이 필요할 때 실제로 입력할 필요는 없습니다.따라서 BuckleScript의 구문을 사용하여 원래 JavaScript에 직접 삽입하고 일반 JavaScript require 문을 작성할 수 있습니다.
[%raw {|require('path/to/myfile.css')|}];
팁 3: JavaScript 구성 요소 사용🤯
다음은 유형 보안에 영향을 주지 않고 기존 JavaScript React 구성 요소를 사용하는 방법에 대한 예입니다.
[@bs.module "path/to/Button.js"] [@react.component]
external make: (
~children: React.element,
~variant: string,
~color: string,
~onClick: ReactEvent.Form.t => unit
) => React.element = "default";
SVGR 사용
SVGR는 SVG를 자동으로 React 구성 요소로 변환할 수 있는 좋은 도구입니다.
앞의 프롬프트를 사용하여 SVGR을 통해 SVG 구성 요소를 React 구성 요소로 자동으로 안전하게 가져올 수 있습니다.
[@bs.module "./times.svg"] [@react.component]
external make: (~height: string) => React.element = "default";
Make sure to install the corresponding Webpack loader and add the necessary Webpack configuration.
팁 4: 네트워크 가져오기 요청 실행
React 애플리케이션에서 네트워크 요청을 수행하려면 Fetch을 사용해야 합니다.
다음은 POST 요청을 위해 Fetch 위에 자신의 패키지를 만드는 방법에 대한 예입니다.
let post = (url, payload) => {
let stringifiedPayload = payload |> Js.Json.object_ |> Js.Json.stringify;
Js.Promise.(
Fetch.fetchWithInit(
url,
Fetch.RequestInit.make(
~method_=Post,
~body=Fetch.BodyInit.make(stringifiedPayload),
~headers=Fetch.HeadersInit.make({"Content-Type":
"application/json"}),
(),
),
)
|> then_(Fetch.Response.json)
);
};
다른 종류의 요청에 따라 이 패키지를 조정할 수 있습니다.
팁 5: JSON 작업
Reason에 내장된 JSON 처리가 아직 올바르지 않습니다.이 시리즈의 두 번째 부분에서 저는 제3자 라이브러리를 사용하지 않은 상황에서 JSON 응답을 성공적으로 반서열화했습니다.
/* src/Request.re */
exception PostError(string);
let post = (url, payload) => {
let stringifiedPayload = payload |> Js.Json.object_ |> Js.Json.stringify;
Js.Promise.(
Fetch.fetchWithInit(
url,
Fetch.RequestInit.make(
~method_=Post,
~body=Fetch.BodyInit.make(stringifiedPayload),
~headers=Fetch.HeadersInit.make({"Content-Type": "application/json"}),
(),
),
)
|> then_(Fetch.Response.json)
|> then_(response =>
switch (Js.Json.decodeObject(response)) {
| Some(decodedRes) =>
switch (Js.Dict.get(decodedRes, "error")) {
| Some(error) =>
switch (Js.Json.decodeObject(error)) {
| Some(decodedErr) =>
switch (Js.Dict.get(decodedErr, "message")) {
| Some(errorMessage) =>
switch (Js.Json.decodeString(errorMessage)) {
| Some(decodedErrorMessage) =>
reject(PostError(decodedErrorMessage))
| None => reject(PostError("POST_ERROR"))
}
| None => resolve(decodedRes)
}
| None => resolve(decodedRes)
}
| None => resolve(decodedRes)
}
| None => resolve(Js.Dict.empty())
}
)
);
};
그러나 나는 이 해결 방안에 대해 만족하지 않는다. 왜냐하면 그것은 커다란 패턴이 지옥과 일치하기 때문이다.
그때부터 지역사회의 도움으로 저는 제3자 도서관을 사용하는 좋은 선택을 찾았습니다.
bs json
bs-json를 사용하면 같은 결과를 매우 간결하게 실현할 수 있습니다.목표는bsjson을 사용하여 json을 기록으로 변환하는 것입니다.
우리는 먼저 기록 유형을 성명한다.우리의 예에서, 우리는response JSON 대상을 처리해야 한다. 선택할 수 있는 오류 JSON 대상이 있다.우리는 이렇게 할 수 있다.
type error = {message: string};
type response = {
error: option(error),
idToken: string,
};
그런 다음 함수를 작성하여 JSON 객체(응답 및 오류)를 디코딩할 수 있습니다.
module Decode = {
let error = json => Json.Decode.{message: json |> field("message", string)};
let response = json =>
Json.Decode.{
error: json |> field("error", optional(error)),
idToken: json |> field("idToken", string),
};
};
마지막으로 우리는 디코더를 사용하여 수신된 JSON을 쉽게 디코딩할 수 있습니다.
|> then_(json => {
let response = Decode.response(json);
switch (response.error) {
| Some(err) => reject(PostError(err.message))
| None => resolve(response)
};
})
ppx_decco
또 다른 JSON 해석을 실현하는 우아한 방법은 ppx_decco 모듈을 사용하는 것이다.
먼저 기록을 명시하고 [@decco]
decorator를 사용하여 미리 처리합니다.
[@decco]
type error = {message: string};
[@decco]
type response = {error: option(error)};
그러면 under the hood 2 함수를 생성하여 해당 JSON 값을 반서열화합니다.
/* MyContextProvider.re */
let context = React.createContext(() => ());
let makeProps = (~value, ~children, ()) => {
"value": value,
"children": children,
};
let make = React.Context.provider(context);
[@react.component]
let make = (~children) => {
<MyContextProvider value="foo">
children
</MyContextProvider>
}
module ChildConsumer = {
[@react.component]
let make = (~children) => {
let contextValue = React.useContext(MyContextProvider.context);
};
[%raw {|require('path/to/myfile.css')|}];
[@bs.module "path/to/Button.js"] [@react.component]
external make: (
~children: React.element,
~variant: string,
~color: string,
~onClick: ReactEvent.Form.t => unit
) => React.element = "default";
[@bs.module "./times.svg"] [@react.component]
external make: (~height: string) => React.element = "default";
Make sure to install the corresponding Webpack loader and add the necessary Webpack configuration.
let post = (url, payload) => {
let stringifiedPayload = payload |> Js.Json.object_ |> Js.Json.stringify;
Js.Promise.(
Fetch.fetchWithInit(
url,
Fetch.RequestInit.make(
~method_=Post,
~body=Fetch.BodyInit.make(stringifiedPayload),
~headers=Fetch.HeadersInit.make({"Content-Type":
"application/json"}),
(),
),
)
|> then_(Fetch.Response.json)
);
};
/* src/Request.re */
exception PostError(string);
let post = (url, payload) => {
let stringifiedPayload = payload |> Js.Json.object_ |> Js.Json.stringify;
Js.Promise.(
Fetch.fetchWithInit(
url,
Fetch.RequestInit.make(
~method_=Post,
~body=Fetch.BodyInit.make(stringifiedPayload),
~headers=Fetch.HeadersInit.make({"Content-Type": "application/json"}),
(),
),
)
|> then_(Fetch.Response.json)
|> then_(response =>
switch (Js.Json.decodeObject(response)) {
| Some(decodedRes) =>
switch (Js.Dict.get(decodedRes, "error")) {
| Some(error) =>
switch (Js.Json.decodeObject(error)) {
| Some(decodedErr) =>
switch (Js.Dict.get(decodedErr, "message")) {
| Some(errorMessage) =>
switch (Js.Json.decodeString(errorMessage)) {
| Some(decodedErrorMessage) =>
reject(PostError(decodedErrorMessage))
| None => reject(PostError("POST_ERROR"))
}
| None => resolve(decodedRes)
}
| None => resolve(decodedRes)
}
| None => resolve(decodedRes)
}
| None => resolve(Js.Dict.empty())
}
)
);
};
type error = {message: string};
type response = {
error: option(error),
idToken: string,
};
module Decode = {
let error = json => Json.Decode.{message: json |> field("message", string)};
let response = json =>
Json.Decode.{
error: json |> field("error", optional(error)),
idToken: json |> field("idToken", string),
};
};
|> then_(json => {
let response = Decode.response(json);
switch (response.error) {
| Some(err) => reject(PostError(err.message))
| None => resolve(response)
};
})
[@decco]
type error = {message: string};
[@decco]
type response = {error: option(error)};
error_decode
response_decode
|> then_(response =>
switch (response_decode(response)) {
| Belt.Result.Ok({error: Some({message})}) =>
reject(PostError(message))
| response => resolve(response)
}
)
결론
이 시리즈는 React 응용 프로그램의 ReasonML 구축을 진실하게 반영하기 위한 것이다.일반적인 프로덕션 환경에서 사용하는 UI 기능과 유사한 UI 기능을 구축함으로써 Google은 좋은 경험과 프로덕션에서 Reason을 사용하기로 결정하면 어려움을 겪게 될 것입니다.
부인할 수 없는 것은, Reason은 강력한 유형 시스템을 가지고 있으며, 매우 강력한 유형 추리를 가지고 있어, 너로 하여금 신뢰할 수 있는 코드를 작성하게 할 수 있다.이 시리즈에서는 React 응용 프로그램이 Reason을 사용하는 개발 속도도 영향을 받지 않는다는 것을 보았다.그래서, 그렇습니다. Reason은 이미 생산에서 React 응용 프로그램을 만들 준비가 되어 있습니다!
특히 Forums와 Discord에 올라온 리슨 커뮤니티, 특히 글을 지속적으로 읽고 도움을 주셔서 감사합니다.
Reference
이 문제에 관하여(생산 응용의 이유는?🤔 (섹션 4)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/seif_ghezala/reasonml-for-production-react-apps-part-4-385d
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(생산 응용의 이유는?🤔 (섹션 4)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/seif_ghezala/reasonml-for-production-react-apps-part-4-385d텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)