ESNext #5: 동적 렌더링과 사이드바에 커스텀 필드 편집

지난 포스트에서는 블록의 속성값에 대해 간단하게 알아 보았다. 블록이 어떻게 자신의 값을 저장하고 표현하는지 알 수 있었다.

블록은 HTML 주석 부분에 블록이 필요한 데이터를 JSON 형태로 저장하거나, 자신이 가지고 있는 HTML 마크업 구조에서 가져올 수 있고, 또 커스텀 필드로부터 가져올 수 있다. 단, 블록 자체는 HTML 코드 그대로 기록하기 때문에 이런 동적인 값들을 표현하려면 생짜 HTML 코드를 사용할 수 없을 것이다.

마크업 구조나 주석에 표현된 JSON을 사용하려면 리액트의 콤포넌트를 활용하거나, 메타 값을 표현하려면 동적인 렌더링을 활용해야 할 것이다.

이번에는 이런 것들을 표현할 수 있도록 해 보자. 이번에 만들 블록의 요구 조건은 다음과 같이 정리해 볼 수 있을 것이다.

  • 블록은 커스텀 필드의 값을 받아 동적 렌더링을 한다.
  • 블록은 마크업의 요소, 주석의 JSON 데이터를 받아 동적으로 값을 처리한다.
  • 블록의 속성값은 사이드바를 활용할 수 있도록 한다.

완성된 코드는 Github 레포지터리에 올려두었다.

예제 설명

예제는 ‘Dynamic Render’라는 블록을 생성한다. 이 블록은 이전처럼 name과 anotherName 속성을 가지고 Hello, World! 처럼 문자를 출력하는 단순한 역할을 한다. 그러나 이 값은 보다 동적이다.

name은 따로 텍스트 입력 상자로부터 가져오며, anotherName은 사이드바로부터 온다. 또 name은 주석에 있는 블록 속성에 저장하며 anotherName은 커스텀 필드 _another_name에 저장한다.

커스텀 블록의 edit() 메소드 결과.
사이드바에서 Another Name을 편집한다.
프론트에 그린 것.

사이드바나 커스텀 블록을 만드는 것은 기존 예제와 크게 다를 것이 없다. 그러나 사이드바에 넣은 값이 메타 필드와 연동되어야만 한다는 점이 이 예제의 키 포인트라고 할 수 있겠다. 그리고 이번에는 save() 메소드는 사실상 아무것도 하지 않는다. 프론트 렌더링을 PHP 측에서 담당하기 때문이다.

렌더 콜백

우선 프론트 쪽 렌더링을 살펴보자. PHP 코드에서 register_block_type() 호출시 ‘editor_script’ 뿐 아니라 ‘render_callback’ 또한 지정해 준다.

register_block_type(
	'wp-estnext-study/wes05-dynaic-render',
	[
		'editor_script'   => 'wes05-dynamic-render',  // 필수!
		'render_callback' => 'wes05_render_callback', // 동적 렌더링.
	]
);

render callback 함수를 실제 작성해 보니, 이 함수는 관리자 페이지에서 포스트 편집 화면에서도, REST API 호출 때에도, 프론트에서도 다 불리는 것을 확인했다. 단순히 프론트에서 호출할 때만을 상정하고 이 함수를 작성하면 프론트 이외 작업에서 에러가 날 수 있다.

render_callback을 프론트에서만 호출한다고 생각하고 작성하면 포스트 수정시 다음처럼 오류가 발생한다. 출력 내용이 REST API 응답시 JSON 호출 전에 먼저 불려버려 클라이언트가 JSON 문서 파싱시 에러를 일으키게 한다.

또한 관리자에서 포스트 편집 화면에 들어갈 때 잠깐의 화면 공백이 발생하는데, 그 때에도 이 출력이 나온다. 그러므로 렌더 콜백은 다음과 같은 if … else … 구문을 사용하여 구분하는 것이 좋을 것이다.

if ( is_admin() ) {
	// 관리자 편집 화면 진입시
} elseif ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
	// REST API 호출시
} else {
	// 프론트 호출은 여기서.
}

사이드바 컨트롤과 커스텀 필드 연동

사이드바에서 TextControl 하나를 넣어 onClick 이벤트와 value 속성을 커스텀 필드의 값과 이어지도록 처리 한다. 그런데 커스텀 필드는 블록 속성이 아니고, 코어가 포스트 편집 화면을 위해 이미 불러와져 있는 상태이다. register_meta() 함수를 부를 때 우리는 ‘show_in_rest’ 항목에 true를 주었기 때문이다.

그런데 이 커스텀 필드를 불러오거나 업데이트해야 할 때는 조금 복잡하다. 아무튼 현재 수준에서 가능한 설명을 기록한다. 우선 TextControl을 하나 감싸 ‘DynamicRender’라고 하자.

let DynamicRender = ({anotherName, onChange}) => {
    return (
        <TextControl
            label="Another Name"
            value={anotherName}
            onChange={onChange}
        />
    );
}

이제 DynamicRender에 마법을 부려 보자. 메타 값을 불러와 컨트롤의 속성으로 넣어 주려면 아래 코드를 참고한다.

// withSelect 로 DynamicRender 함수를 래핑.
DynamicRender = withSelect(select => {
    const {getEditedPostAttribute} = select('core/editor');
    return {
        anotherName: getEditedPostAttribute('meta')['_another_name']
    };
})(DynamicRender);

한편 메타 값을 다시 업데이트하려면 아래 코드를 작성한다.

// withDispatch 로 DynamicRender 함수를 다시 래핑.
DynamicRender = withDispatch(dispatch => {
    const {editPost} = dispatch('core/editor');
    return {
        onChange(value) {
            editPost({meta: {_another_name: value}});
        }
    }
})(DynamicRender);

Redux와 워드프레스 자바스크립트 코어가 겹치는 부분이라 어렵고 이해가 잘 안가는 부분이 있다. 이해하려 해도 파야 할 부분이 많아 보여 현재는 코드 조각 수준밖에는 이해하지 못하는게 불만이다. 보다 이해를 높이려면 리액트나 리덕스를 보다 이해해야만 알 수 있을 것 같다. 보다 시간과 노력이 필요한 부분인듯.

댓글 남기기