Skip to content
Mithril.js 2
Main Navigation 가이드API

한국어

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
Italiano
Polski
Türkçe
čeština
magyar

한국어

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
Italiano
Polski
Türkçe
čeština
magyar

외관

Sidebar Navigation

시작하기

설치

간단한 애플리케이션

리소스

JSX

구형 브라우저에서 ES6+ 사용하기

애니메이션

테스트

예제

타사 통합

경로 처리

주요 개념

Virtual DOM 노드

컴포넌트

생명주기 메서드

키

자동 리드로우 시스템

기타

프레임워크 비교

v1.x에서 v2.x로의 마이그레이션

v0.2.x에서 v2.x로 마이그레이션하기

API

이 페이지에서

v1.x에서 v2.x로의 마이그레이션 ​

v2.x는 v1.x와 거의 완벽하게 API 호환되지만, 몇 가지 호환성에 영향을 주는 변경 사항이 있습니다.

vnode.state에 할당 ​

v1.x에서는 vnode.state를 자유롭게 조작하고 값을 할당할 수 있었습니다. 하지만 v2.x에서는 vnode.state에 직접 할당하려고 하면 오류가 발생합니다. 마이그레이션 방법은 여러 가지가 있지만, 대부분의 경우 vnode.state에 대한 참조를 vnode.state.foo로 변경하고, foo에 적절한 이름(예: 카운터의 현재 값인 count)을 지정하는 것으로 간단하게 해결할 수 있습니다. v2.x에서는 직접 할당을 시도하면 오류가 발생합니다.

v1.x ​

javascript
var Counter = {
  oninit: function (vnode) {
    vnode.state = 0;
  },
  view: function (vnode) {
    return m('.counter', [
      m(
        'button',
        {
          onclick: function () {
            vnode.state--;
          },
        },
        '-'
      ),
      vnode.state,
      m(
        'button',
        {
          onclick: function () {
            vnode.state++;
          },
        },
        '+'
      ),
    ]);
  },
};

v2.x ​

javascript
var Counter = {
  oninit: function (vnode) {
    vnode.state.count = 0;
  },
  view: function (vnode) {
    return m('.counter', [
      m(
        'button',
        {
          onclick: function () {
            vnode.state.count--;
          },
        },
        '-'
      ),
      vnode.state.count,
      m(
        'button',
        {
          onclick: function () {
            vnode.state.count++;
          },
        },
        '+'
      ),
    ]);
  },
};

v1.0이 처음 릴리스되었을 때 클래스 및 클로저 컴포넌트가 존재하지 않았으므로 vnode.tag에서 필요한 정보를 가져왔습니다. 이러한 구현 방식 덕분에 가능했으며, 일부 문서에서는 이를 암시하기도 했습니다. 이제는 상황이 달라졌으며, 상태에 대한 참조가 두 개가 아닌 하나만 있으므로 구현 관점에서 관리가 더 쉬워졌습니다.

라우트 앵커 변경 사항 ​

v1.x에서는 oncreate: m.route.link를 사용하여 라우팅 가능한 vnode를 생성하고, 링크가 변경될 수 있는 경우 onupdate: m.route.link도 사용했습니다. 이들은 각각 라우팅 가능한 vnode의 라이프사이클 훅으로 사용되었습니다. v2.x에서는 이제 m.route.Link 컴포넌트를 사용해야 합니다. m("a", ...) 외의 다른 엘리먼트를 사용하는 경우, selector: 속성을 통해 선택자를 지정할 수 있습니다. 옵션은 options:로, 비활성화 여부는 disabled:로 지정할 수 있으며, href: (필수)를 포함한 다른 속성들은 인라인으로 지정할 수 있습니다. selector: 자체는 m의 첫 번째 인수로 유효한 모든 선택기를 포함할 수 있으며, [href=...] 및 [disabled] 속성은 일반 옵션뿐만 아니라 선택기에서도 지정할 수 있습니다.

v1.x ​

javascript
m('a', {
  href: '/path',
  oncreate: m.route.link,
});

m('button', {
  href: '/path',
  oncreate: m.route.link,
});

m('button.btn[href=/path]', {
  oncreate: m.route.link,
});

v2.x ​

javascript
m(m.route.Link, {
  href: '/path',
});

m(m.route.Link, {
  selector: 'button',
  href: '/path',
});

m(m.route.Link, {
  selector: 'button.btn[href=/path]',
});

m.request 오류 변경 사항 ​

v1.x에서 m.request는 JSON 호출에서 오류를 파싱하고, 파싱된 결과 객체의 속성을 응답에 할당했습니다. 예를 들어 HTTP 상태 코드가 403이고 응답 본문이 {"code": "backoff", "timeout": 1000}인 경우, 오류 객체에 err.code = "backoff" 및 err.timeout = 1000과 같은 속성이 추가되었습니다.

v2.x에서는 응답이 결과 객체의 response 속성에 할당되고, code 속성에는 HTTP 상태 코드가 포함됩니다. 따라서 HTTP 상태 코드가 403이고 응답 본문이 {"code": "backoff", "timeout": 1000}인 경우, 오류 객체에는 err.response = {code: "backoff", timeout: 1000} 및 err.code = 403 속성이 할당됩니다.

m.withAttr 제거됨 ​

v1.x에서는 이벤트 리스너를 oninput: m.withAttr("value", func)와 같이 사용할 수 있었습니다. v2.x에서는 이벤트의 대상에서 직접 값을 읽어야 합니다. 스트림과 함께 사용하면 유용했지만, m.withAttr("value", stream) 형태의 사용 빈도가 m.withAttr("value", prop)에 비해 현저히 낮았기 때문에 m.withAttr는 제거되었습니다.

v1.x ​

javascript
var value = '';

// In your view
m('input[type=text]', {
  value: value(),
  oninput: m.withAttr('value', function (v) {
    value = v;
  }),
});

// OR

var value = m.stream('');

// In your view
m('input[type=text]', {
  value: value(),
  oninput: m.withAttr('value', value),
});

v2.x ​

javascript
var value = '';

// In your view
m('input[type=text]', {
  value: value,
  oninput: function (ev) {
    value = ev.target.value;
  },
});

// OR

var value = m.stream('');

// In your view
m('input[type=text]', {
  value: value(),
  oninput: function (ev) {
    value(ev.target.value);
  },
});

m.route.prefix ​

v1.x에서 m.route.prefix는 m.route.prefix(prefix)를 통해 호출되는 함수였습니다. 이제는 m.route.prefix = prefix를 통해 설정하는 속성이 되었습니다.

v1.x ​

javascript
m.route.prefix('/root');

v2.x ​

javascript
m.route.prefix = '/root';

m.request/m.jsonp params 및 body ​

data와 useBody 옵션은 URL에 삽입되어 요청에 추가되는 쿼리 파라미터를 위한 params와, HTTP 요청 본문에 담아 전송할 데이터를 위한 body로 변경되었습니다. 이를 통해 실제 전송되는 HTTP 요청을 더욱 세밀하게 제어할 수 있으며, POST 요청 시에도 쿼리 파라미터를 사용할 수 있고, 본문 데이터를 포함하는 GET 요청을 생성하는 것도 가능합니다.

의미 있는 "body"가 없는 m.jsonp는 params만 사용하므로 data를 params로 이름을 변경하는 것으로 충분합니다.

v1.x ​

javascript
m.request('https://example.com/api/user/:id', {
  method: 'GET',
  data: { id: user.id },
});

m.request('https://example.com/api/user/create', {
  method: 'POST',
  data: userData,
});

v2.x ​

javascript
m.request('https://example.com/api/user/:id', {
  method: 'GET',
  params: { id: user.id },
});

m.request('https://example.com/api/user/create', {
  method: 'POST',
  body: userData,
});

경로 템플릿 ​

v1.x에는 유사하지만 별도로 설계된 2개의 구문과 3개의 다른 구현이 있는 세 개의 개별 경로 템플릿 구문이 있었습니다. 이들은 상당히 임시적인 방식으로 정의되었고 파라미터는 일반적으로 이스케이프되지 않았습니다. 이제 :key 형태는 자동으로 인코딩되고, :key... 형태는 인코딩되지 않은 원시 값으로 처리됩니다. 예상치 못한 인코딩 문제가 발생하면 :path...를 사용하면 됩니다. 간단합니다.

구체적으로 각 메서드에 미치는 영향은 다음과 같습니다.

m.request 및 m.jsonp URL, m.route.set 경로 ​

v2.x에서는 경로 구성 요소가 URL에 삽입될 때 자동으로 이스케이프 처리됩니다. m.route.set("/user/:name/photos/:id", {name: user.name, id: user.id})를 호출한다고 가정합니다. 이전에는 user가 {name: "a/b", id: "c/d"}인 경우 경로가 /user/a%2Fb/photos/c/d로 설정되었지만 이제는 /user/a%2Fb/photos/c%2Fd로 설정됩니다. 만약 키를 이스케이프 처리 없이 URL에 삽입하고 싶다면 :key...를 사용하십시오.

v2.x의 키에는 . 또는 - 문자가 포함될 수 없습니다. v1.x에서는 / 문자를 제외한 모든 문자를 포함할 수 있었습니다.

/api/search?q=:query와 같은 인라인 쿼리 문자열의 보간은 v2.x에서 지원되지 않습니다. 쿼리 문자열에 직접 지정하는 대신, 적절한 키 이름으로 params를 통해 전달해야 합니다.

m.route 라우트 패턴 ​

:key... 형식의 경로 키는 v1.x에서 URL 디코딩된 값을 반환했지만, v2.x에서는 원시 URL을 반환합니다.

과거에는 :key.md와 같은 형태가 잘못 허용되어 keymd: "..."와 같은 파라미터가 생성되기도 했습니다. 이제는 더 이상 허용되지 않습니다. .md는 이제 이름이 아닌 패턴의 일부로 취급됩니다.

라이프사이클 호출 순서 ​

v1.x에서는 컴포넌트 vnode에 정의된 속성 라이프사이클 훅이 항상 컴포넌트 자체의 라이프사이클 훅 보다 먼저 호출되었습니다. v2.x에서는 onbeforeupdate 훅에 대해서만 이러한 순서가 유지됩니다. 따라서 코드에 따라 조정이 필요할 수 있습니다.

v1.x ​

javascript
var Comp = {
  oncreate: function () {
    console.log('Component oncreate');
  },
  view: function () {
    return m('div');
  },
};

m.mount(document.body, {
  view: function () {
    return m(Comp, {
      oncreate: function () {
        console.log('Attrs oncreate');
      },
    });
  },
});

// Logs:
// Attrs oncreate
// Component oncreate

v2.x ​

javascript
var Comp = {
  oncreate: function () {
    console.log('Component oncreate');
  },
  view: function () {
    return m('div');
  },
};

m.mount(document.body, {
  view: function () {
    return m(Comp, {
      oncreate: function () {
        console.log('Attrs oncreate');
      },
    });
  },
});

// Logs:
// Component oncreate
// Attrs oncreate

m.redraw 동기성 ​

v2.x에서 m.redraw()는 항상 비동기 방식으로 동작합니다. 현재 리드로우가 진행 중이 아닐 때, m.redraw.sync()를 호출하여 동기적인 리드로우를 명시적으로 요청할 수 있습니다.

선택기 속성 우선 순위 ​

v1.x에서는 선택기 속성이 속성 객체에 지정된 속성보다 우선했습니다. 예를 들어 m("[a=b]", {a: "c"}).attrs는 {a: "b"}를 반환했습니다.

v2.x에서는 속성 객체에 지정된 속성이 선택기 속성보다 우선합니다. 예를 들어 m("[a=b]", {a: "c"}).attrs는 {a: "c"}를 반환합니다.

기술적으로 이 변경은 v0.2.x의 동작으로 되돌아가는 것입니다.

자식 정규화 ​

v1.x에서는 컴포넌트 vnode의 자식 노드가 다른 vnode와 마찬가지로 정규화되었습니다. v2.x에서는 더 이상 자동 정규화가 이루어지지 않으므로, 이에 맞춰 코드를 조정해야 합니다. 이는 렌더링에서 수행되는 정규화에는 영향을 미치지 않습니다.

m.request 헤더 ​

v1.x에서 Mithril.js는 useBody가 true(기본값)로 설정되고 나열된 다른 조건이 충족되는 경우에만 모든 비-GET 요청에 대해 다음 두 헤더를 설정했습니다.

  • JSON 본문이 있는 요청에 대한 Content-Type: application/json; charset=utf-8
  • JSON 응답을 예상하는 요청에 대한 Accept: application/json, text/*

v2.x에서는 Mithril.js가 JSON 형식의 요청 본문이 존재하고 그 값이 null이 아닐 경우, 모든 요청에 대해 Content-Type 헤더를 application/json; charset=utf-8로 설정합니다. 이는 HTTP 메서드와 상관없이 적용됩니다.

두 헤더 중 첫 번째 헤더인 Content-Type은 지정된 콘텐츠 유형으로 인해 CORS-안전 목록 요청 헤더가 아니므로 CORS 프리플라이트 요청을 트리거하고 서버에서 CORS가 구성된 방식에 따라 새로운 오류가 발생할 수 있습니다. 이로 인해 CORS 관련 문제가 발생한다면, headers: {"Content-Type": "text/plain"}과 같이 Content-Type 헤더를 직접 설정하여 재정의해야 할 수 있습니다. ( Accept 헤더는 아무것도 트리거하지 않으므로 재정의할 필요가 없습니다.)

Fetch 사양에서 CORS 프리플라이트 검사를 피할 수 있는 유일한 콘텐츠 유형은 application/x-www-form-urlencoded, multipart/form-data 및 text/plain입니다. 다른 콘텐츠 유형은 허용하지 않으며, 의도적으로 JSON을 허용하지 않습니다.

라우트의 해시 문자열에 있는 쿼리 파라미터 ​

v1.x에서는 쿼리 문자열과 해시 문자열 모두에서 라우트에 대한 쿼리 파라미터를 지정할 수 있었으므로 m.route.set("/route?foo=1&bar=2"), m.route.set("/route?foo=1#bar=2") 및 m.route.set("/route#foo=1&bar=2")는 모두 동일하게 취급되었고, 추출된 속성은 {foo: "1", bar: "2"}였습니다.

v2.x에서는 해시 문자열의 내용은 무시되지만 보존됩니다. 따라서 각각에서 추출된 속성은 다음과 같습니다.

  • m.route.set("/route?foo=1&bar=2") → {foo: "1", bar: "2"}
  • m.route.set("/route?foo=1#bar=2") → {foo: "1"}
  • m.route.set("/route#foo=1&bar=2") → {}

이렇게 변경된 이유는 https://example.com/#!/route#key와 같은 URL이 URL 사양에 따라 기술적으로 유효하지 않으며, 이전 RFC에서도 유효하지 않았기 때문입니다. 이는 HTML 사양의 특이한 점일 뿐입니다.

또는 간단히 말해, 유효하지 않은 URL 사용을 지양해야 합니다!

키 ​

v1.x에서는 키가 있는 vnode와 키가 없는 vnode를 자유롭게 혼합할 수 있었습니다. 첫 번째 노드에 키가 있는 경우 키가 있는 diff가 수행되어 모든 요소에 키가 있다고 가정하고 키가 없는 노드를 무시했습니다. 그렇지 않으면 반복적인 diff가 수행되고 노드에 키가 있는 경우 태그 등과 유사한 항목이 확인되는 동시에 변경되지 않았는지 확인했습니다.

v2.x에서는 프래그먼트와 요소의 자식 목록이 모두 키가 있거나 키가 없어야 합니다. 여기서 '키가 없는 노드'는 키가 없는 것으로 취급되며, 더 이상 무시되지 않습니다.

해결해야 하는 경우 [m("div", {key: whatever})]와 같이 단일 vnode를 포함하는 프래그먼트 패턴을 사용하십시오.

m.version 제거됨 ​

일반적으로 거의 사용되지 않았고 언제든지 직접 다시 추가할 수 있습니다. 사용 가능한 기능을 파악하기 위해 기능 감지(feature detection)를 사용하는 것이 좋으며, v2.x API는 이러한 기능 감지를 더욱 용이하게 하도록 설계되었습니다.

Pager
이전프레임워크 비교
다음v0.2.x에서 v2.x로 마이그레이션하기

MIT 라이선스 하에 배포되었습니다.

Copyright (c) 2024 Mithril Contributors

https://mithril.js.org/migration-v1x.html

MIT 라이선스 하에 배포되었습니다.

Copyright (c) 2024 Mithril Contributors