首页 文章

如何从类render方法中提取JSX?

提问于
浏览
1

我想为React Native编写类似SCSS的东西:它将解析你的组件jsx和特殊的类SCSS样式,并返回一个通常的RN组件,带有重新设计的样式和jsx .

让我们说我们有这个反应代码:

class MyClass extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>I remember syrup sandwiches</Text>
      </View>
    );
  }
}

我也有SCSS-ish样式,其中父容器中的每个Text组件与容器“class”将具有我们提供的相同道具 .

const styles = StyleSheet.create(
  toRNStyles({
    container: {
      Text: { color: 'red' },
    },
  })
);

最后我们需要这样的输出:

...
<View style={styles.container}>
  <Text style={styles._Text_container}>
    I remember syrup sandwiches
  </Text>
</View>
...

那么如何才能从类外部获取从render方法返回的jsx?

3 回答

  • 2

    你可以为babel编写一个插件,因为react-native使用它来将JSX转换为普通的javascript . 看看这些包:

    • babel-helper-builder-react-jsx

    • babel-plugin-syntax-jsx

    • babel-plugin-transform-react-jsx

    • babel-plugin-transform-react-jsx-source

    • jsx-ast-utils

  • 1

    似乎没有一种标准的方法可以做到这一点 . 但是,您可以导入ReactDOMServer并使用其 renderToStaticMarkup 函数 .

    像这样:

    class MyApp extends React.Component {
      render() {
        var myTestComponent = <Test>bar</Test>;
        console.dir(ReactDOMServer.renderToStaticMarkup(myTestComponent));
        
        return myTestComponent;
      }
    }
    
    const Test = (props) => {
      return (
        <div>
          <p>foo</p>
          <span>{props.children}</span>
        </div>
      );
    }
    
    ReactDOM.render(<MyApp />, document.getElementById("myApp"));
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom-server.js"></script>
    <div id="myApp"></div>
    
  • 1

    我认为解析返回的元素是错误的方法 . 一个挑战是 style 的值将是一个对象( styles.container ===样式键/值的散列),而您需要一个可以映射到对象的键 .

    我认为最可重用的方法是利用React上下文(我假设RN支持!)来构建一个 styleName ,它可以在你下载组件树时进行扩充 .

    这是一个初始方法,它做了一些假设(例如,每个组件都将 styleName 作为prop提供;您可能希望在设计时而不是运行时提供它) . 简而言之,您使用此HOC包装要参与的每个组件,并将 styleName 作为每个组件的prop . 连接这些 styleName 值以生成映射到样式的上下文化名称 .

    这个例子产生:

    <div style="background-color: green; color: red;">
      <div style="color: blue;">Some Text</div>
    </div>
    
    const CascadingStyle = (styles, Wrapped) => class extends React.Component {
      static displayName = 'CascadingStyle';
      
      static contextTypes = {
        styleName: React.PropTypes.string
      }
      
      static childContextTypes = {
        styleName: React.PropTypes.string
      }
      
      // pass the current styleName down the component tree
      // to other instances of CascadingStyle
      getChildContext () {
        return {
          styleName: this.getStyleName()
        };
      }
    
      // generate the current style name by either using the
      // value from context, joining the context value with
      // the current value, or using the current value (in
      // that order).
      getStyleName () {
        const {styleName: contextStyleName} = this.context;
        const {styleName: propsStyleName} = this.props;
        let styleName = contextStyleName;
    
        if (propsStyleName && contextStyleName) {
          styleName = `${contextStyleName}_${propsStyleName}`;
        } else if (propsStyleName) {
          styleName = propsStyleName;
        }
    
        return styleName;
      }
      
      // if the component has styleName, find that style object and merge it with other run-time styles
      getStyle () {
        if (this.props.styleName) {
            return Object.assign({}, styles[this.getStyleName()], this.props.styles);
        }
    
        return this.props.styles;
      }
      
      render () {
        return (
          <Wrapped {...this.props} style={this.getStyle()} />
        );
      }
    };
    
    const myStyles = {
      container: {backgroundColor: 'green', color: 'red'},
      container_text: {color: 'blue'}
    };
    
    const Container = CascadingStyle(myStyles, (props) => {
      return (
        <div {...props} />
      );
    });
    
    const Text = CascadingStyle(myStyles, (props) => {
      return (
        <div {...props} />
      );
    });
    
    const Component = () => {
      return (
        <Container styleName="container">
          <Text styleName="text">Some Text</Text>
        </Container>
      );
    };
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    

相关问题