2017-03-07 1 views
0

마크 업의 데이터 특성을 사용하여 명시 적으로로드 할 수없는 시나리오에서 내 React 구성 요소를 동적으로로드하는 작업 솔루션 (아래)이 있습니다. 나는 'eval'을 사용하여 구성 요소 레지스트리에서 동적 구성 요소를 얻는 방법을 알고 있으며 더 나은 솔루션을 찾고 있습니다.악의적 인 평가를 사용하지 않고 React 구성 요소의 동적 렌더링

export default class DynamicComponentRenderer { 

/** 
* Creates an instance of DynamicComponentRenderer. 
* 
* @param {object} element The DOM element to make into a component. 
* 
* @memberOf DynamicComponentRenderer 
*/ 
constructor(element, componentRegistry) { 
    Guard.throwIf(element, "element"); 
    Guard.throwIf(componentRegistry, "componentRegistry"); 

    this.element = element; 
    this.componentName = element.getAttribute("data-react-component"); 
    this.DynamicComponent = eval(`componentRegistry.${this.componentName}`); 
    this.props = {}; 

    if (!this.DynamicComponent) { 
     throw new Error(`Unable to create a component of the name '${this.componentName}'.`) 
    } 

    Array.prototype.slice.call(element.attributes).filter((attrib) => 
     (attrib.name.includes('data-') && !attrib.name.includes('data-react-component')) 
    ).forEach((attrib) => { 
     this.props[attrib.name.replace(/data-/i, '').replace(/-[a-z]/, (match) => { 
      return match.toUpperCase(); 
     }).replace(/-/, '')] = attrib.value; 
    }); 
} 

/** 
* Renders the dynamic React component. 
* 
* @returns Rendered HTML. 
* 
* @memberOf DynamicComponentRenderer 
*/ 
render() { 
    ReactDOM.render(React.createElement(this.DynamicComponent, this.props), this.element); 
} 
} 

이처럼 조금 보이는 구성 요소 색인 파일입니다에 전달 된 componentRegistry ...

export default { 
    DataList: DataList, 
    Form: { 
     Buttons : { 
      Submit: SubmitButton, 
      Cancel: CancelButton 
     } 
    } 
    OwnedAddress: OwnedAddress 
} 

DynamicComponentRegister는 JsComponentManager에 의해로드됩니다 ...

import PathManager from "../../SharedJs/path-manager"; 
import AppComponents from "./components/index.jsx"; 
import Dynamic from "../../SharedJs/components/dynamic-component-renderer"; 

export default class JsComponentManager { 

    constructor(onLoader, pathManager) { 
     this.loader = onLoader; 
     this.pathManager = pathManager; 
     this.select = { 
      reactComponents:() => $(".js-react-component") 
     } 
    } 

    bindComponents() { 
     const paths = new PathManager(); 
     let $reactComponents = this.select.reactComponents() 
     if ($reactComponents.length > 0) { 
      this.loader.add(this.renderReactComponents, $reactComponents); 
     } 
    } 

    renderReactComponents($elements) { 
     $.makeArray($elements).forEach((el) => { 
      let dynamicRenderer = new Dynamic(el, AppComponents); 
      document.DynamicRenderers = document.DynamicRenderers || []; 
      document.DynamicRenderers.push(dynamicRenderer); 
      dynamicRenderer.render(); 
     }); 
    } 
} 

PathManager가 현재 인스턴스에서 아무 작업도 수행하지 않습니다 (URL을 조회하고 URL로 구성 요소를 렌더링 할 수 있지만 지금은 수행하지 않습니다). 생성자에 전달 된 'onLoader'는 onLoad 이벤트에 대한 이벤트를 대기열에 넣습니다.

+0

eval('componentRegistry.${this.componentName}'); 

는 자바 스크립트를 일반 아닌가 교체는 componentRegistry이 = {데이터 목록이 : DataList에}하자'??이 충분 오브젝트'어디'DataList'이 당신의 컴포넌트에 액세스하는 동안 'this.DynamicComponent = componentRegistry ['dataList ']'? –

+0

클래스의 목적은 런타임에 형식을 알 수없는 경우를위한 것입니다. 이를 통해 서버 및 클라이언트에서 생성 된 코드 요소를 함께 묶을 수 있습니다. 컴포넌트 레지스트리가 평평하지 않다. (예제 개선) –

+0

나는 이것을 듣고 싶지는 않다고 생각하지만, 최선의 해결책은'componentRegistry' 객체를 평평하게하는 것이다. –

답변

1

일부 개체를 통과하는 경로를 확인하기 위해 eval을 사용하는 경우 대신 개체를 통과하도록 설계된 함수를 사용할 수 있습니다.

const traverseInternal = (object, keys, keyIndex) => { 
    if (keyIndex >= keys.length) { 
    return object; 
    } 

    return traverseInternal(object[keys[keyIndex]], keys, keyIndex + 1); 
}; 

const traverse = (object, deepKey) => { 
    return traverseInternal(object, deepKey.split('.'), 0); 
}; 

그런

traverse(componentRegistry, this.componentName); 
+0

그건 꽤 깔끔한 해결책입니다. 나는 그것을 시도 할 것이다. –

관련 문제