Atualize a foto do perfil com visualização com React.js e jQuery

Atualizar uma foto de perfil com uma visualização é um recurso que permite aos usuários visualizar e ajustar sua foto de perfil antes de ser permanentemente aplicado. 

Neste tutorial, aprenderemos como implementar um componente React.js simples que permite ao usuário selecionar uma imagem, visualizá-la e manipular a própria imagem para envio por meio de uma chamada AJAX.

Configurar

Primeiro, crie um componente que mantenha dois estados: um para a imagem em si e outro para o URL de origem da visualização. Em seguida, você precisará do componente para renderizar uma interface que contém um elemento de entrada para seleção de arquivo, uma seção para visualização da imagem e um botão para acionar a funcionalidade de upload. O componente PictureUploader inicialmente terá a seguinte aparência:

import React from 'react';
import $ from 'jquery';

export default class PictureUploader extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      picture: false,
      src: false
    }
  }

  render() {
    return (
      <div>
        <h5>Picture Uploader</h5>

        <input
          type="file"
        />
        <br/>
        <div>
          <p>
            No Preview
          </p>
        </div>
        <hr/>
        <button>
          Upload
        </button>
      </div>
    );
  }
}

Estados a Manter

Dentro da estrutura do componente, existem dois valores de estado:

  • picture: Uma referência ao arquivo de imagem selecionado pelo usuário
  • src: O valor do URL de origem para a visualização da nossa imagem

Ambos os valores são inicialmente definidos como false quando o componente é criado.

Interface de usuário

O conteúdo renderizado é uma interface com três seções principais:

  1. Uma interface para permitir ao usuário selecionar uma imagem de seu computador
<input type="file"/>

2. Uma seção de visualização para quando o usuário seleciona a imagem. Por enquanto, aparecerá "Sem visualização" dentro de um elemento <p>.

<p>
  No Preview
</p>

3. Um botão para acionar o upload

<button>
  Upload
</button>

Seleção de arquivo de imagem

Em seguida, programe um manipulador de eventos que processará a imagem sempre que o usuário selecionar uma imagem para carregar. Depois, crie outra função para lidar com a pré-visualização da imagem. Se nenhuma imagem for selecionada, retorne "Sem visualização" texto. Caso contrário, retorne uma tag HTML img contendo o URL da imagem selecionada.

Função manipuladora de eventos

O manipulador de eventos extrairá a imagem do arquivo e criará uma URL para a visualização. Copie o seguinte código do manipulador para seu componente:

handlePictureSelected(event) {
  var picture = event.target.files[0];
  var src     = URL.createObjectURL(picture);

  this.setState({
    picture: picture,
    src: src
  });
}

Este método aceita um argumento event cuja propriedade target representa o elemento de entrada ao qual este manipulador está vinculado. Neste caso, espera-se que seu input elemento do tipo file tenha uma propriedade files, que é do tipo de dados array. Portanto, para obter o arquivo que o usuário selecionou, faça referência ao primeiro elemento do array:

var picture = event.target.files[0];

A variável src representa o URL para a visualização da imagem. Você pode criar isso chamando URL.createObjectURL(), que aceita um objeto de arquivo. Isso cria uma URL temporária anexada à variável global document. Isto significa que se a página for atualizada, você perderá essa referência de URL. Neste caso, o objeto de arquivo é picture.

var src = URL.createObjectURL(picture);

Finalmente atualize o estado do seu componente usando this.setState().

this.setState({
  picture: picture,
  src: src
});

Vinculando ainput

Vincule a função ao atributo de entrada do arquivo onChange:

<input
  type="file"
  onChange={this.handlePictureSelected.bind(this)}
/>

Anexar .bind(this) permitirá que this ainda retenha seu valor, referindo-se à instância do componente mesmo dentro de handlePictureSelected método.

Visualização de renderização

Nossa seção de visualização é resultado de outra função que contém uma instrução if/else. Ele verifica o estado do componente src se não for falso, indicando que você possui um valor. Nesse caso, retorne o código JSX que contém um img cuja origem é src. Caso contrário, retorne o código JSX que contém o texto "Sem visualização."

renderPreview() {
  if(this.state.src) {
    return (
      <img src={this.state.src}/>
    );
  } else {
    return (
      <p>
        No Preview
      </p>
    );
  }
}

Invoque esse método dentro do render() método do componente, especificamente como um substituto para a opção "Sem visualização" texto que você recebeu inicialmente.

<div>
{this.renderPreview()}
</div>

Acionar upload

Função manipuladora de eventos

Crie um método chamado upload que contenha uma ajax() chamada de jQuery para realizar o upload. Copie o seguinte código para seu componente:

upload() {
  var formData = new FormData();

  formData.append("file", this.state.picture);

  $.ajax({
    url: "/some/api/endpoint",
    method: "POST",
    data: formData,
    cache: false,
    contentType: false,
    processData: false,
    success: function(response) {
      // Code to handle a succesful upload
    }
  });
}

Observe que em vez de passar um objeto JavaScript simples e antigo, você cria uma instância de FormData para permitir incorporar o objeto de imagem. Faça isso invocando append de formData, que aceita dois argumentos:

  • "file": uma string que representa a chave do parâmetro a ser processada pelo servidor.
  • this.state.picture: o próprio objeto de imagem extraído de state.
var formData = new FormData();
formData.append("file", this.state.picture);

Como você está passando FormData como data em sua chamada AJAX POST, você tem que definir cache, contentType e processData como falso. Para url, substitua "/some/api/endpoint" pelo ponto final real onde você enviaria sua foto.

Vincular ao botão

Vincule o manipulador de eventos para fazer upload ao atributo onClick do seu elemento de botão:

  <button
    onClick={this.upload.bind(this)}
  >
    Upload
  </button>

Semelhante à sua ligação input, anexar .bind(this) permitirá que this ainda se refira à instância do componente, mesmo dentro do manipulador upload.

Código geral

O código final ficará assim:

import React from 'react';
import $ from 'jquery';

export default class PictureUploader extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      picture: false,
      src: false
    }
  }

  handlePictureSelected(event) {
    var picture = event.target.files[0];
    var src     = URL.createObjectURL(picture);

    this.setState({
      picture: picture,
      src: src
    });
  }

  renderPreview() {
    if(this.state.src) {
      return (
        <img src={this.state.src}/>
      );
    } else {
      return (
        <p>
          No Preview
        </p>
      );
    }
  }

  upload() {
    var formData = new FormData();

    formData.append("file", this.state.picture);

    $.ajax({
      url: "/some/api/endpoint",
      method: "POST",
      data: formData,
      cache: false,
      contentType: false,
      processData: false,
      success: function(response) {
        // Code to handle a succesful upload
      }
    });
  }

  render() {
    return (
      <div>
        <h5>Picture Uploader</h5>

        <input
          type="file"
          onChange={this.handlePictureSelected.bind(this)}
        />
        <br/>
        <div>
        {this.renderPreview()}
        </div>
        <hr/>
        <button
          onClick={this.upload.bind(this)}
        >
          Upload
        </button>
      </div>
    );
  }
}

O processo para criar um componente que pode processar arquivos de imagem carregados pelo usuário de seu computador é o mesmo que qualquer outro tratamento de eventos baseado em React.js.

1.60 GEEK