React es un framework impresionante creado por un grupo de programadores increíbles de Facebook. Implementa un DOM virtual, que agrega al instante los componentes necesarios y elimina al instante los que no se necesitan, de forma similar al DOM. React desempeña el papel de la V en la estructura MVC, pero si lo usas junto con Flux, tienes un framework impresionante que permite sincronizar fácilmente la M y la V. Lo de Flux lo dejamos para más adelante ~

Componentes

En React, puedes crear un componente con una funcionalidad especial que no encontrarías ni buscando con una lámpara entre los elementos HTML, como el menú desplegable de este tutorial. Cada componente tiene su propio ámbito (scope), por lo que una vez que definimos un componente, podemos usarlo una y otra vez, ¡sin necesidad de interactuar con otros componentes!

Cada componente tiene una función llamada render, que puede devolver de manera eficiente el HTML que se va a mostrar en el navegador. También podemos invocar otros componentes de React, lo que significa que una vez que entras en React es como adentrarse en un mar profundo; oh, no, es que no hay límites para lo que se puede hacer.

JSX

Si prestas atención a React con frecuencia, quizás descubras que existe algo llamado JSX. JSX nos permite escribir HTML dentro de JavaScript, en lugar de usar HTML que contiene JavaScript. Nos ayuda a desarrollar rápidamente porque no tenemos que preocuparnos por cadenas y saltos de línea, etc. Puedes ejecutar JSX en el navegador, pero no se recomienda porque ralentizaría la velocidad de tu página. Gulp y Grunt proporcionan un intérprete de JSX para tus tareas de preprocesamiento, así que si quieres usar JSX, te recomiendo activar esta funcionalidad.

Usando JSX

Como se dijo anteriormente, en JSX cada componente tiene un método render que produce un "ViewModel (modelo de vista)": antes de devolver HTML al componente, puedes incorporar la información de este modelo (ViewModel) en la vista, lo que significa que tu HTML cambiará dinámicamente según este modelo (por ejemplo, una lista dinámica).

Una vez que hayas terminado la operación, puedes devolver lo que quieras renderizar (render). Usar JSX para hacerlo es así de simple.

var ExampleComponent = React.createClass({
    render: function () {
        return (
            <div className="navigation">
                Hello World!
            </div>
            );
    }
});

Si intentas ejecutar este código en tu navegador, solo obtendrás un error de sintaxis, porque en JavaScript los caracteres < y > deben estar entre comillas. Cuando ejecutas el intérprete de JSX sobre el código, se convertirá a esto.

var ExampleComponent = React.createClass({
    render: function () {
        return (
            React.createElement('div', {className: 'navigation'}, 'Hello World!')
            );
    }
});

Puedes hacer clic aquí para probar el ejemplo.- Estoy usando el intérprete de JSX del navegador (no se recomienda, pero es para JSFiddle).

¡Funcionó! JSX interpretó lo que generaste con React.createElementtodoslos nodos del DOM, generando el tipo de nodo, los parámetros y el contenido. Puedes prescindir de JSX, pero eso significa que tendrás que escribir manualmente todos los nodos del DOM además de React.createElement. Muchísimos ejemplos me dicen que use JSX.

Seguramente te preguntarás por qué uso className en el DOM en lugar de class. Esto se debe a que class es una palabra reservada de JavaScript. Cuando JSXinterpretatu código, convierte todos los atributos del nodo en un objeto, ¡pero no puedes usar un objeto como atributo!

Usando variables en atributos

Si quieres cambiar dinámicamente la clase de estilo del componente (o cualquier otro valor de atributo), puedes usar variables. Sin embargo, no puedes simplemente pasar el nombre de una variable; también debes envolverlo entre llaves, para que JSX sepa que es una variable externa.

var ExampleComponent = React.createClass({
render: function () {
    var navigationClass = 'navigation';
    return (
        <div className={ navigationClass }>
            Hello World!
        </div>
        );
}
});

Puedes ver esta funcionalidad aquí.

El renderizador inicial

Cuando vas a renderizar un componente de React por primera vez, necesitas decirle a React qué componente renderizar y también especificar un nodo DOM existente para indicar dónde renderizar ese componente. Para ello, usarás la función React.render.

var ExampleComponent = React.createClass({
render: function () {
    return (
        <div className="navigation">
            Hello World!
        </div>
        );
}
});
React.render(<ExampleContent />, document.body);

Renderizará el componente en el nodo body: ¡sencillo! A partir de ahí puedes invocar otros componentes como de costumbre, o si lo prefieres, puedes usar la función render muchas veces, si no quieres usar React para renderizar toda la página pero aún así quieres usar varios componentes.

Fundamentos de un componente

Los componentes pueden tener su propio "estado". Esto nos permite reutilizar el mismo componente muchas veces pero haciendo que se vean completamente diferentes, porque el estado de cada instancia del componente es único.

Cuando pasas propiedades a un componente, se llaman propiedades (props). No te limites solo a los atributos HTML; puedes pasar cualquier cosa que quieras y acceder a ella dentro del componente mediante this.props. Esto nos permite reutilizar el mismo componente pero pasándole un conjunto diferente de propiedades, como la "configuración" del componente.

Propiedades

Según nuestro ejemplo anterior de "Hello World!", tenemos un atributo className en el nodo HTML. Dentro del componente, podemos acceder a ese valor usando this.props.classname, pero como se mencionó antes, puedes pasar cualquier cosa que quieras. Para nuestro menú desplegable, necesitamos configurar la navegación como un objeto, y el componente lo usará como la configuración a renderizar. ¡Empecemos—

var navigationConfig = [];

var Navigation = React.createClass({
    render: function () {
        return (
            <div className="navigation">

            </div>
            );
    }
});

React.render(<Navigation config={ navigationConfig } />, document.body);

Si ahora pudiéramos acceder a this.props.config, recibiríamos un array vacío (el valor de navigationConfig). Antes de pasar a la codificación de la navegación real, expliquemos primero el estado.

Estado

Como se discutió antes, cada componente tiene su propio "estado". Cuando quieras usar el estado, debes definir el estado inicial y luego puedes usar this.setState para actualizarlo. Cada vez que el estado se actualiza, el componente vuelve a llamar a la función render, utilizando los nuevos valores para reemplazar o modificar los valores renderizados anteriormente. Este es el secreto del DOM virtual: el algoritmo de cálculo de diferencias se realiza internamente en React, por lo que no tenemos que depender de las actualizaciones del DOM (porque el DOM es lento). React calcula las diferencias y genera un conjunto de instrucciones (por ejemplo, añadir la clase 'active' a 'navigation__link', o eliminar un nodo) y las ejecuta en el DOM.

Con la navegación, mantendremos el menú desplegable abierto en el estado. Para ello, agrega una función getInitialState al objeto de configuración de la clase y devuelve un objeto con el estado inicial que queremos.

var navigationConfig = [];

var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    render: function () {
        return (
            <div className="navigation">

            </div>
            );
    }
});

React.render(<Navigation config={ navigationConfig } />, document.body);

Notarás que lo establecimos en -1. Cuando nos dispongamos a abrir un menú desplegable, usaremos la posición del elemento de navegación en el array de configuración dentro del estado, y como los índices del array comienzan en 0, tenemos que usar -1 para indicar que aún no se apunta a ningún elemento de navegación.

Podemos usar this.state para acceder al estado, por lo que si observamos this.state.openDropdown, debería devolverse -1.

Ciclo de vida de los componentes

Cada componente tiene su "ciclo de vida": es una serie de funciones que puedes definir en la configuración del componente y que se invocarán durante la vida del componente. Ya hemos visto getInitialState: solo se llama una vez, cuando el componente se monta.

componentWillMount

Esta función se llama cuando el componente va a ser montado. Esto significa que podemos ejecutar aquí el código necesario para el funcionamiento del componente. Debido a que render se llama varias veces durante el ciclo de vida del componente, generalmente colocamos aquí el código que solo necesita ejecutarse una vez, como las solicitudes XHR.

var ExampleComponent = React.createClass({
    componentWillMount: function () {
        // xhr request here to get data
    },
    render: function () {
        // this gets called many times in a components life
        return (
            <div>
                Hello World!
            </div>
            );
    }
});

componentDidMount

Una vez que tu componente ha ejecutado la función render y realmente ha renderizado el componente en el DOM, se llama a componentDidMount. Aquí podemos realizar cualquier operación DOM que necesitemos, así como cualquier cosa que requiera que el componente ya exista realmente en el DOM, como por ejemplo renderizar un gráfico. Puedes acceder al nodo DOM de forma interna llamando a this.getDOMNode.

var ExampleComponent = React.createClass({
    componentDidMount: function () {
        var node = this.getDOMNode();
        // render a chart on the DOM node
    },
    render: function () {
        return (
            <div>
                Hello World!
            </div>
            );
    }
});

componentWillUnmount

Si te dispones a eliminar el componente del DOM, esta función será llamada. Esto nos permite hacer una limpieza detrás del componente, como eliminar cualquier listener de eventos que hayamos vinculado. Si nosotrosnohacemos la limpieza detrás de nosotros, y cuando uno de esos eventos se dispara, intentará calcular un componente que no está cargado, y React lanzará un error.

var ExampleComponent = React.createClass({
    componentWillUnmount: function () {
        // unbind any event listeners specific to this component
    },
    render: function () {
        return (
            <div>
                Hello World!
            </div>
            );
    }
});

Métodos de los componentes

React también proporciona métodos para que nos sea más fácil trabajar con los componentes. Se invocarán durante el proceso de creación del componente. Por ejemplo, getInitialState nos permite definir un estado predeterminado, de modo que no tengamos que preocuparnos por hacer verificaciones adicionales sobre si los elementos del estado existen en el código.

getDefaultProps

Cuando creamos un componente, podemos definir valores predeterminados para las propiedades del componente según lo que queramos. Esto significa que al llamar al componente, si no se les asignan valores a estas propiedades, el componente tendrá una "configuración" predeterminada, y no tendremos que preocuparnos por verificar propiedades en la siguiente línea de código.

Cuando defines el componente, estas propiedades predeterminadas se almacenan en caché, por lo que son iguales para cada instancia del componente y no se pueden cambiar. Para el componente de navegación, especificamos la configuración como un array vacío, de modo que incluso si no se pasa ninguna configuración, no se producirá un error dentro del método render.

var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    getDefaultProps: function () {
        return {
            config: []
        }
    },
    render: function () {
        return (
            <div className="navigation">

            </div>
            );
    }
});

React.render(<Navigation config={ navigationConfig } />, document.body);

propTypes

También podemos especificar libremente el tipo de cada propiedad. Esto es muy útil para verificar y manejar asignaciones inesperadas de propiedades. Como en el dropdown a continuación, especificamos que solo los arrays pueden colocarse en la configuración.

var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    getDefaultProps: function () {
        return {
            config: []
        }
    },
    propTypes: {
        config: React.PropTypes.array
    },
    render: function () {
        return (
            <div className="navigation">

            </div>
            );
    }
});

React.render(<Navigation config={ navigationConfig } />, document.body);

mixins

También podemos añadir mixins a los componentes. Es un componente básico independiente de React (solo una configuración de tipo objeto). Esto significa que, si tenemos dos componentes con funcionalidad similar, podemos compartir una configuración (si el estado inicial es el mismo). Podemos crear un método de forma abstracta en el mixin, para no tener que escribir el mismo código dos veces.

var ExampleMixin = {
    componentDidMount: function () {
        // bind some event listeners here
    },
    componentWillUnmount: function () {
        // unbind those events here!
    }
};

var ExampleComponent = React.createClass({
    mixins: [ExampleMixin],
    render: function () {
        return (
            <div>
                Hello World!
            </div>
            );
    }
});

var AnotherComponent = React.createClass({
    mixins: [ExampleMixin],
    render: function () {
        return (
            <div>
                Hello World!
            </div>
            );
    }
});

De esta manera todos los componentes tienen los mismos métodos componentDidMount y componentWillUnmount, ahorrándonos el código reescrito. De todos modos, no puedes hacer override (sobrescribir) estas propiedades; si esta propiedad está configurada en el mixin, no se puede sobrescribir en este componente.

Iteración y bucles

Cuando tenemos un array que contiene objetos, ¿cómo recorremos este array y renderizamos cada objeto en un elemento de lista? JSX te permite usarlo en cualquier archivo JavaScript; puedes mapear el array y devolver JSX, y luego usar React para renderizarlo.

var navigationConfig = [
    {
        href: 'http://ryanclark.me',
        text: 'My Website'
    }
];
var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    getDefaultProps: function () {
        return {
            config: []
        }
    },
    propTypes: {
        config: React.PropTypes.array
    },
    render: function () {
        var config = this.props.config;
        var items = config.map(function (item) {
            return (
                <li className="navigation__item">
                    <a className="navigation__link" href={ item.href }>
                        { item.text }
                    </a>
                </li>
                );
        });
        return (
            <div className="navigation">
                { items }
            </div>
            );
    }
});
React.render(<Navigation config={ navigationConfig } />, document.body);

En JSFiddle, siéntete libre de usar navigationConfigin

La configuración de navegación se compone de arrays y objetos, e incluye un atributo href que apunta al enlace y un atributo text para mostrar. Cuando mapeamos, recorre el array uno a uno para obtener los objetos. Podemos acceder a href y text, y usarlos en HTML. Al devolver la lista, los elementos de lista de este array serán reemplazados, así que cuando lo pasamos a React para que lo procese, ¡sabrá cómo renderizarlo!

Combinación

Hasta ahora, hemos logrado desplegar todos los menús desplegables. Necesitamos saber qué elemento está desplegado; usaremos la propiedad .children para recorrer nuestro array navigationConfig. A continuación, podemos operar sobre los elementos hijos del desplegable mediante un bucle.

var navigationConfig = [
    {
        href: 'http://ryanclark.me',
        text: 'My Website',
        children: [
            {
                href: 'http://ryanclark.me/how-angularjs-implements-dirty-checking/',
                text: 'Angular Dirty Checking'
            },
            {
                href: 'http://ryanclark.me/getting-started-with-react/',
                text: 'React'
            }
        ]
    }
];
var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    getDefaultProps: function () {
        return {
            config: []
        }
    },
    propTypes: {
        config: React.PropTypes.array
    },
    render: function () {
        var config = this.props.config;
        var items = config.map(function (item) {
            var children, dropdown;
            if (item.children) {
                children = item.children.map(function (child) {
                    return (
                        <li className="navigation__dropdown__item">
                            <a className="navigation__dropdown__link" href={ child.href }>
                                { child.text }
                            </a>
                        </li>
                    );
                });
                dropdown = (
                    <ul className="navigation__dropdown">
                        { children }
                    </ul>
                );
            }
            return (
                <li className="navigation__item">
                    <a className="navigation__link" href={ item.href }>
                        { item.text }
                    </a>
                    { dropdown }
                </li>
                );
        });
        return (
            <div className="navigation">
                { items }
            </div>
            );
    }
});
React.render(<Navigation config={ navigationConfig } />, document.body);

El ejemplo está aquí- Pero todavía podemos ver los elementos desplegados, aunque hayamosopenDropdown configurado como-1 。

Podemos acceder en el componente athis.state, para determinar si el desplegable está abierto, y podemos añadirle una nueva clase CSS para mostrar el efecto hover del ratón.

var navigationConfig = [
    {
        href: 'http://ryanclark.me',
        text: 'My Website',
        children: [
            {
                href: 'http://ryanclark.me/how-angularjs-implements-dirty-checking/',
                text: 'Angular Dirty Checking'
            },
            {
                href: 'http://ryanclark.me/getting-started-with-react/',
                text: 'React'
            }
        ]
    }
];
var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    getDefaultProps: function () {
        return {
            config: []
        }
    },
    openDropdown: function (id) {
        this.setState({
            openDropdown: id
        });
    },
    closeDropdown: function () {
        this.setState({
            openDropdown: -1
        });
    },
    propTypes: {
        config: React.PropTypes.array
    },
    render: function () {
        var config = this.props.config;
        var items = config.map(function (item, index) {
            var children, dropdown;
            if (item.children) {
                children = item.children.map(function (child) {
                    return (
                        <li className="navigation__dropdown__item">
                            <a className="navigation__dropdown__link" href={ child.href }>
                                { child.text }
                            </a>
                        </li>
                    );
                });
                var dropdownClass = 'navigation__dropdown';
                if (this.state.openDropdown === index) {
                    dropdownClass += ' navigation__dropdown--open';
                }
                console.log(this.state.openDropdown, index);
                dropdown = (
                    <ul className={ dropdownClass }>
                        { children }
                    </ul>
                );
            }
            return (
                <li className="navigation__item" onMouseOut={ this.closeDropdown } onMouseOver={ this.openDropdown.bind(this, index) }>
                    <a className="navigation__link" href={ item.href }>
                        { item.text }
                    </a>
                    { dropdown }
                </li>
                );
        }, this);
        return (
            <div className="navigation">
                { items }
            </div>
            );
    }
});
React.render(<Navigation config={ navigationConfig } />, document.body);

Ver el ejemplo aquí– Al pasar el ratón por "My Website", el desplegable se mostrará.

Anteriormente, he añadido eventos de ratón a cada elemento de lista. Como puedes ver, estoy usando.binduna llamada con (bind), en lugar de otras formas de llamada – esto se debe a que, cuando el ratón del usuario sale del área del elemento, no nos importa dónde está el cursor; todo lo que necesitamos saber es cerrar el desplegable, por lo que podemos establecer su valor en -1. Pero necesitamos saber qué elemento se ha desplegado cuando el ratón entra, así que necesitamos ese parámetro (el índice del elemento). Usamos la llamada con bind en lugar de simplemente pasar una función porque necesitamos que sea React quien la invoque. Si la llamamos directamente, tendríamos que llamarla constantemente, en lugar de llamarla en el evento.

Ahora podemos añadir muchos elementos anavigationConfig dentro de ello, y también podemos añadirle estilos a la funcionalidad desplegable.Ver ejemplo。

Resumen

React es un framework simple, conveniente, fácil de usar y potente. Su API concisa permite crear rápidamente tus propios componentes, sin tener que preocuparte por el complejo DOM ni realizar operaciones especialmente complicadas; se desempeña muy bien sobre todo en elementos de lista repetidos.

Fuente: http://www.oschina.net/translate/getting-started-with-react