Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert string to jsx in react native

I'm trying to display javascript string as jsx, it seems there's no way of display a string as jsx in react native, e.g. const test = '<Text>hello</Text>' render() { return ({test})}.

Given the following string

const svg = '<Svg.G fill="none" fill-rule="evenodd"> <Svg.Path fill="none" d="M0 0h24v24H0z"/> <Svg.Path stroke="#333" stroke-linecap="round" stroke-linejoin="round" d="M3.5 12.5h17v9h-17zM13.5 12.5v9M10.5 12.5v9M1.883 9.602l18.353-4.918.776 2.898L2.66 12.5z"/> <Svg.Path stroke="#333" stroke-linejoin="round" d="M6 6.857c.957.553 4.675.393 4.675.393S8.957 3.945 8 3.393a2 2 0 1 0-2 3.465zM15.296 4.366c-.546.956-3.852 2.674-3.852 2.674s-.164-3.718.388-4.674a2 2 0 1 1 3.464 2z"/> <Svg.Path stroke="#333" stroke-linecap="round" stroke-linejoin="round" d="M12.508 6.755l.777 2.897M9.61 7.531l.776 2.899"/></Svg.G>';

Then I want render it like the following

render() {
    return (
      <View>
        <Svg>
          {svg}
        </Svg>
      </View>
    );
}

This renders nothing, How can I render this string, or maybe I should turn the string into an array and render it as an array?

like image 256
TenTen Peter Avatar asked Jun 29 '18 19:06

TenTen Peter


2 Answers

It's not an answer to your question, but maybe it helps you to figure out how to do what you want. I strongly not recommend using this approach ;)

So you can't just use eval for this string because you need to convert jsx to js. Babel doing it for us on building stage, but you can parse a string and convert it to React.createElement shape.

It will work only if you know what format of string with components you receive

I provide example only for your example (<Text>hello</Text>) because it is much easier, but it'll help you get an idea.

import React, { PureComponent } from 'react';
import RN, { View } from 'react-native';

function mapStringToComponent(stringToRender) {
    const parseResult = stringToRender.match(/<([a-z]*)>(.*)<\/[a-z]*>/i);
     // result of this regex ["<Text>hello</Text>", "Text", "hello"]

    if (parseResult !== null) {
      const [, compName, innerText] = parseResult;

      return React.createElement(
        RN[compName],
        null, // here may be an object with attributes if your node has any
        innerText,
      );
    }

    return null;
}


export default class MyDynamicComponent extends PureComponent {
  render() {
    const component = mapStringToComponent('<Text>hello</Text>');

    return (
      <View>
       {component}
      </View>
    );
  };
}

Here you can check how should looks your converted svg string: babel link

I've tried to google some lib that can do it for you but hasn't found any. Maybe I'm bad at googling :)

like image 138
Oleksandr Blyzniuk Avatar answered Oct 16 '22 19:10

Oleksandr Blyzniuk


Well we could do this using import react-jsx-parser Added a line to filter out the lines and spaces as parser throws an error when their is space in the SVG code

Eg.

    var svg = `<Svg
    width={286}
    height={335}
    viewBox="0 0 286 335"
    fill="none"
    xmlns="http://www.w3.org/2000/svg"
    {...props}
    >
    <Path
      d="M63.763 25.066h17.72L107.542 1l14.593 16.741L248.258 32.39V140.16L284.74 257.35c-3.822 3.488-20.013 15.486-54.202 35.575-51.7 25.112-174.419 37.668-229.315 40.807l11.465-193.571c5.56.698 23.557 1.675 51.075 0 34.398-2.092 37.525 2.093 43.779-15.694 6.254-17.788-6.254-35.576-13.55-49.178-5.838-10.882-22.585-14.997-30.229-15.695V25.065z"
      fill="#F8F9F8"
      stroke="#22223B"
      strokeOpacity={0.8}
      strokeWidth={1.06988}
      strokeLinecap="round"
      strokeDasharray="6.42 6.42"
    />
    <Path
    onPress={handleOnPress}
      transform="rotate(3.757 16.59 146.446)"
      fill="#9A8C98"
      fillOpacity={0.22}
      d="M16.5894 146.446H40.5513V192.058H16.5894z"
    />
  </Svg>`
    svg = svg.replace(/\n/g, ' ').replace(/\>[\t ]+\</g, "><");
    return (
        <JsxParser
            components={{ Svg, Path }}
            renderInWrapper={false}
            bindings={{
                foo: 'foo',
                handleOnPress: () => alert('sasas'),
            }}
            blacklistedAttrs={[]} // this line should fix your issue
            jsx={svg}
        />
    );
like image 33
Abhi Burk Avatar answered Oct 16 '22 19:10

Abhi Burk