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

时间:2017-06-27 15:19:03

标签: javascript reactjs react-native

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

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

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 个答案:

答案 0 :(得分:2)

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

  • 巴别辅助助洗剂反应的-JSX
  • 巴别-插件 - 句法 - JSX
  • 巴别-插件变换反应的-JSX
  • 巴别-插件变换反应的-JSX源
  • JS​​X-AST-utils的

答案 1 :(得分: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>

答案 2 :(得分:1)

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

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

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

这个例子产生:

<div style="background-color: green; color: red;">
  <div style="color: blue;">Some Text</div>
</div>

&#13;
&#13;
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>
  );
};
&#13;
<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>
&#13;
&#13;
&#13;