Bastante impresión JSON con React

92

Estoy usando ReactJS y parte de mi aplicación requiere JSON bastante impreso.

Obtengo algo de JSON como:, { "foo": 1, "bar": 2 }y si lo ejecuto JSON.stringify(obj, null, 4)en la consola del navegador, se imprime bastante, pero cuando lo uso en este fragmento de reacción:

render: function() {
  var json = this.getStateFromFlux().json;
  return (
    <div>
      <JsonSubmitter onSubmit={this.onSubmit} />
      { JSON.stringify(json, null, 2) }
    </div>
  );
},

genera JSON bruto que parece "{ \"foo\" : 2, \"bar\": 2}\n".

¿Cómo consigo que esos personajes se interpreten correctamente? {

Brandon
fuente
4
¿Usted ha intentado JSON.stringify(json, null, "\t")?
brroshan
Resulta que tuve un error tonto por el cual this.getStateFromFlux().jsonya estaba devolviendo una cadena. Lo modifiqué para contener un objeto JS en su lugar, y ahora funciona perfectamente.
Brandon
1
ver también github.com/alexkuz/react-json-tree
Aprillion

Respuestas:

191

Deberá insertar la BRetiqueta de forma adecuada en la cadena resultante o utilizar, por ejemplo, una PREetiqueta para que se mantenga el formato de stringify:

var data = { a: 1, b: 2 };

var Hello = React.createClass({
    render: function() {
        return <div><pre>{JSON.stringify(data, null, 2) }</pre></div>;
    }
});

React.render(<Hello />, document.getElementById('container'));

Ejemplo de trabajo .

Actualizar

class PrettyPrintJson extends React.Component {
    render() {
         // data could be a prop for example
         // const { data } = this.props;
         return (<div><pre>{JSON.stringify(data, null, 2) }</pre></div>);
    }
}

ReactDOM.render(<PrettyPrintJson/>, document.getElementById('container'));

Ejemplo

Componente funcional sin estado, React .14 o superior

const PrettyPrintJson = ({data}) => {
    // (destructured) data could be a prop for example
    return (<div><pre>{ JSON.stringify(data, null, 2) }</pre></div>);
}

O ...

const PrettyPrintJson = ({data}) => (<div><pre>{ 
    JSON.stringify(data, null, 2) }</pre></div>);

Ejemplo de trabajo

Memo / 16.6+

(Es posible que incluso desee utilizar una nota, 16.6+)

const PrettyPrintJson = React.memo(({data}) => (<div><pre>{
    JSON.stringify(data, null, 2) }</pre></div>));
WiredPrairie
fuente
2
¡Gracias por esto! No sabía sobre el parámetro JSON.stringify-opcional. Javascript es increíble ^^
Marcel Ennix
React ahora está en desuso, use ReactDOM en su lugar
Brane
Esto es perfecto: ¡la solución más simple es siempre la mejor! Recomiendo agregar highlight.js para resaltar la sintaxis y dar un toque de tema.
KeepingItClassy
esto es hermoso
JChao
La solución de etiquetas <pre> funciona perfectamente y esa es la forma correcta.
Vikram K
20

Solo para extender un poco la respuesta de WiredPrairie, un mini componente que se puede abrir y cerrar.

Puede usarse como:

<Pretty data={this.state.data}/>

ingrese la descripción de la imagen aquí

export default React.createClass({

    style: {
        backgroundColor: '#1f4662',
        color: '#fff',
        fontSize: '12px',
    },

    headerStyle: {
        backgroundColor: '#193549',
        padding: '5px 10px',
        fontFamily: 'monospace',
        color: '#ffc600',
    },

    preStyle: {
        display: 'block',
        padding: '10px 30px',
        margin: '0',
        overflow: 'scroll',
    },

    getInitialState() {
        return {
            show: true,
        };
    },

    toggle() {
        this.setState({
            show: !this.state.show,
        });
    },

    render() {
        return (
            <div style={this.style}>
                <div style={this.headerStyle} onClick={ this.toggle }>
                    <strong>Pretty Debug</strong>
                </div>
                {( this.state.show ?
                    <pre style={this.preStyle}>
                        {JSON.stringify(this.props.data, null, 2) }
                    </pre> : false )}
            </div>
        );
    }
});

Actualizar

Un enfoque más moderno (ahora que createClass está a punto de desaparecer)

import styles from './DebugPrint.css'

import autoBind from 'react-autobind'
import classNames from 'classnames'
import React from 'react'

export default class DebugPrint extends React.PureComponent {
  constructor(props) {
    super(props)
    autoBind(this)
    this.state = {
      show: false,
    }
  }    

  toggle() {
    this.setState({
      show: !this.state.show,
    });
  }

  render() {
    return (
      <div style={styles.root}>
        <div style={styles.header} onClick={this.toggle}>
          <strong>Debug</strong>
        </div>
        {this.state.show 
          ? (
            <pre style={styles.pre}>
              {JSON.stringify(this.props.data, null, 2) }
            </pre>
          )
          : null
        }
      </div>
    )
  }
}

Y tu archivo de estilo

.root {backgroundColor: '# 1f4662'; color: '#fff'; fontSize: '12px'; }

.header {backgroundColor: '# 193549'; relleno: '5px 10px'; fontFamily: 'monospace'; color: '# ffc600'; }

.pre {pantalla: 'bloque'; relleno: '10px 30px'; margen: '0'; desbordamiento: 'desplazamiento'; }

Chris
fuente
¡Seguro que es un +1 increíble! Hago pequeñas cosas como esta para depurar y probar datos antes de construir el componente en sí. ¡Este es realmente asombroso!
Ryan Hamblin
1
Para convertir a componente: toddmotto.com/react-create-class-versus-component
whitneyland
11

' React-json-view ' proporciona una solución que representa la cadena json.

import ReactJson from 'react-json-view';
<ReactJson src={my_important_json} theme="monokai" />
Aborn Jiang
fuente
5
const getJsonIndented = (obj) => JSON.stringify(newObj, null, 4).replace(/["{[,\}\]]/g, "")

const JSONDisplayer = ({children}) => (
    <div>
        <pre>{getJsonIndented(children)}</pre>
    </div>
)

Entonces puedes usarlo fácilmente:

const Demo = (props) => {
   ....
   return <JSONDisplayer>{someObj}<JSONDisplayer>
}
Ben Carp
fuente
0

Aquí hay una demostración react_hooks_debug_print.htmlde react hooks que se basa en la respuesta de Chris. El ejemplo de datos json es de https://json.org/example.html .

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</title>
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

    <!-- Don't use this in production: -->
    <script src="https://unpkg.com/[email protected]/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>
    <script src="https://raw.githubusercontent.com/cassiozen/React-autobind/master/src/autoBind.js"></script>

    <script type="text/babel">

let styles = {
  root: { backgroundColor: '#1f4662', color: '#fff', fontSize: '12px', },
  header: { backgroundColor: '#193549', padding: '5px 10px', fontFamily: 'monospace', color: '#ffc600', },
  pre: { display: 'block', padding: '10px 30px', margin: '0', overflow: 'scroll', }
}

let data = {
  "glossary": {
    "title": "example glossary",
    "GlossDiv": {
      "title": "S",
      "GlossList": {
        "GlossEntry": {
          "ID": "SGML",
          "SortAs": "SGML",
          "GlossTerm": "Standard Generalized Markup Language",
          "Acronym": "SGML",
          "Abbrev": "ISO 8879:1986",
          "GlossDef": {
            "para": "A meta-markup language, used to create markup languages such as DocBook.",
            "GlossSeeAlso": [
              "GML",
              "XML"
            ]
          },
          "GlossSee": "markup"
        }
      }
    }
  }
}

const DebugPrint = () => {
  const [show, setShow] = React.useState(false);

  return (
    <div key={1} style={styles.root}>
    <div style={styles.header} onClick={ ()=>{setShow(!show)} }>
        <strong>Debug</strong>
    </div>
    { show 
      ? (
      <pre style={styles.pre}>
       {JSON.stringify(data, null, 2) }
      </pre>
      )
      : null
    }
    </div>
  )
}

ReactDOM.render(
  <DebugPrint data={data} />, 
  document.getElementById('root')
);

    </script>

  </body>
</html>

O de la siguiente manera, agregue el estilo en el encabezado:

    <style>
.root { background-color: #1f4662; color: #fff; fontSize: 12px; }
.header { background-color: #193549; padding: 5px 10px; fontFamily: monospace; color: #ffc600; }
.pre { display: block; padding: 10px 30px; margin: 0; overflow: scroll; }
    </style>

Y reemplácelo DebugPrintcon lo siguiente:

const DebugPrint = () => {
  // /programming/30765163/pretty-printing-json-with-react
  const [show, setShow] = React.useState(false);

  return (
    <div key={1} className='root'>
    <div className='header' onClick={ ()=>{setShow(!show)} }>
        <strong>Debug</strong>
    </div>
    { show 
      ? (
      <pre className='pre'>
       {JSON.stringify(data, null, 2) }
      </pre>
      )
      : null
    }
    </div>
  )
}
caot
fuente