react 对象克隆_使用React和Cloudinary构建自己的Giphy克隆

react 对象克隆

Cover Image We’ve all seen and used them… animated GIFs they are funny, distracting and seem to be everywhere. We have Alex Chung and Jace Cooke to thank for this incredible distraction and waste of everyone’s time. Seriously. It’s a distraction. The initial idea came to them over breakfast. There is now over 250 million users, and the company raised $55 million in funding at a $300 million valuation.

Founder Alex Chung - 2016 SXSW

Wouldn’t it be awesome if you could build your own Giphy Alternative in about the same amount of time it takes to eat your frosted flakes?

如果您可以在吃磨砂片所需的大致相同的时间内构建自己的Giphy Alternative,那就太棒了吗?

我们将建立什么 ( What We'll Build )

You have been tasked with creating a Giphy Alternative in record time and immediately wonder how to do that. The client can’t wait and you need something to show to them ASAP. Well, look no further; In this tutorial, we will be building our version of Giphy which utilizes Cloudinary for the hosting and transformation of our files. We’ll also be able to create tiny GIFs that we can share with the world. By the end of this tutorial, our app will have the following features:

您的任务是在创纪录的时间内创建Giphy Alternative,立即想知道如何做到这一点。 客户迫不及待,您需要尽快向他们展示一些内容。 好吧,别再看了。 在本教程中,我们将构建我们的Giphy版本,该版本利用Cloudinary托管和转换文件。 我们还将能够创建可以与世界共享的微小GIF。 在本教程结束时,我们的应用将具有以下功能:

  • Users should be able to sign up and log in.

    用户应该能够注册并登录。
  • Registered users should be able to upload animated GIFs (hosted GIFs included) via the platform.

    注册用户应该能够通过平台上传动画GIF(包括托管GIF)。
  • Registered and unregistered users should be able to view all the animated GIFs on a dashboard.

    已注册和未注册的用户应该能够在仪表板上查看所有动画GIF。
  • Users should able to share those GIFs on Facebook and Twitter.

    用户应该能够在Facebook和Twitter上共享这些GIF。
  • Users will be able to convert videos to GIFs and download them. Shall we begin?

    用户将能够将视频转换为GIF并下载。 让我们开始?

配置 ( Setting Up )

We will build our app using React and set it up using the create-react-app tool. Just navigate to your dev folder and run the command below in your terminal.

我们将使用React构建我们的应用程序,并使用create-react-app工具对其进行设置。 只需导航至您的dev文件夹,然后在终端中运行以下命令即可。

create-react-app cliphycd cliphy 

Let’s use bootstrap and material bootstrap theme to style the application. For bootstrap, open up the index.html in the public folder of the application and add the following line where you would normally put your styles:

让我们使用引导程序和材料引导程序主题来设置应用程序样式。 对于引导,请在应用程序的公用文件夹中打开index.html ,并在通常放置样式的位置添加以下行:

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

Grab the CSS for the bootstrap material design, copy it to your public/css folder and reference it in your index.html:

获取用于引导程序材料设计CSS ,将其复制到public/css folder ,并在index.html中引用它:

<link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap-material-design.min.css">

认证方式 ( Authentication )

Install auth0-js and the following modules with the following command:

使用以下命令安装auth0-js和以下模块:

npm i auth0-js react-router@3.0.0 jwt-decode axios

auth0-js - For authentication react-router - For routing within our app jwt-decode - For decoding the JSON Web Token in our app axios - For making network requests. Create components and utils folders under your src directory. In the utils folder, create a file AuthService.js and add this code to it. (See the ReactJS Authentication Tutorial by unicodeveloper to ensure you are on the right track).

auth0-js-用于身份验证react-router-用于在我们的应用程序中进行路由jwt-decode-用于在我们的应用程序axios中解码JSON Web令牌-用于发出网络请求。 在src目录下创建componentsutils文件夹。 在utils文件夹中,创建一个文件AuthService.js并将此代码添加到其中。 (请参阅unicodeveloper提供的ReactJS身份验证教程,以确保您处在正确的轨道上)。

创建我们的组件 ( Creating Our Components )

First let’s add Navigation and then create the different components that we need in our application. Now create a Nav.js in the components folder and the following piece of code to it.

首先,我们添加导航,然后创建我们的应用程序所需的不同组件。 现在,在components文件夹中创建一个Nav.js ,并为其添加以下代码。

import React, { Component } from 'react';
import { Link } from 'react-router';
import { login, logout, isLoggedIn } from '../utils/AuthService';
import { uploadWidget } from '../utils/WidgetHelper';

import '../App.css';

class Nav extends Component {

    render() {
        return (
            <nav className="navbar navbar-inverse">
                <div className="container-fluid">
                    <div className="navbar-header">
                        <Link className="navbar-brand" to="/">Cliphy</Link>
                    </div>
                    <div>
                        <ul className="nav navbar-nav">
                            <li>
                                <Link to="/">All Gifs</Link>
                            </li>
                            <li>
                                <Link to="/create">Create Gif</Link>
                            </li>
                        </ul>
                        <ul className="nav navbar-nav navbar-right">
                            <li>
                                {
                                    (isLoggedIn()) ? <button type="button" className="btn btn-raised btn-sm btn-default" >Upload Gif</button> : ''
                                }
                            </li>
                            <li>
                                {
                                    (isLoggedIn()) ?
                                        (
                                            <button type="button" className="btn btn-raised btn-sm btn-danger" onClick={() => logout()}>Log out </button>
                                        ) : (
                                            <button className="btn btn-sm btn-raised btn-default" onClick={() => login()}>Log In</button>
                                        )
                                }
                            </li>
                        </ul>
                    </div>
                </div>
            </nav>
        )
    }
}
export default Nav;

Go ahead and create a Dashboard.js file and add this code to it:

继续创建Dashboard.js文件,并将以下代码添加到其中:

import React, { Component } from 'react';
import { Link } from 'react-router';
import axios from 'axios';

import Nav from './Nav';

class Dashboard extends Component {
    state = {
        gifs: []
    };

    render() {
        const { gifs } = this.state;
        return (
            <div>
                <Nav />
                <div className="row">
                    <h3 className="col-md-12"> The Dashboard</h3>
                </div>
            </div>
        );
    }
}

export default Dashboard;

Let’s create another component named create.js. This component will be empty for now. We’ll come back to it later. components/Create.js

让我们创建另一个名为create.js组件。 该组件暂时为空。 我们稍后会再讨论。 组件/Create.js

import React, { Component } from 'react';
import Nav from './Nav';

class Create extends Component {}

export default Create;

Uploading GIFs As mentioned earlier, we will be using Cloudinary to handle our images, including uploading and manipulating them. To start, let’s create an account on cloudinary.com. Uploading with Cloudinary is a breeze, using the simple Upload Widget. It enables you to upload files from various sources. So we are going to reference it in our application. Open your index.html file and add the following code to the bottom of your page.

上载GIF如前所述,我们将使用Cloudinary来处理图像,包括上载和操作它们。 首先,让我们在cloudinary.com上创建一个帐户。 使用简单的Upload Widget,使用Cloudinary进行上传很容易。 它使您可以从各种来源上载文件。 因此,我们将在我们的应用程序中引用它。 打开index.html文件,并将以下代码添加到页面底部。

<script src="//widget.cloudinary.com/global/all.js" type="text/javascript"></script> 

Now, create a file called WidgetHelper.js in the utils folder and add the following piece of code to it.

现在,在utils文件夹中创建一个名为WidgetHelper.js的文件,并向其中添加以下代码。

export function uploadWidget(cloudinarySettings, cb) {
    window.cloudinary
        .openUploadWidget(cloudinarySettings, (err, res) => {
            console.error(err);
            cb(res);
        });
}

We will make some changes to our Nav.js to trigger the upload widget. Modify your Nav.js file to look like this:

我们将对Nav.js进行一些更改以触发上传小部件。 修改Nav.js文件,使其如下所示:

import React, { Component } from 'react';
import { Link } from 'react-router';
import { login, logout, isLoggedIn } from '../utils/AuthService';
import { uploadWidget } from '../utils/WidgetHelper';
import '../App.css';
import Create from './Create';
class Nav extends Component {
    uploadGif() {
        let cloudinarySettings = {
            cloud_name: '<CLOUD_NAME>',
            upload_preset: '<UPLOAD_PRESET>',
            tags: ['cliphy'],
            sources: ['local', 'url', 'google_photos', 'facebook'],
            client_allowed_formats: ['gif'],
            keep_widget_open: true,
            theme: 'minimal',
        }
        uploadWidget(cloudinarySettings, (res) => {
            console.log(res);
        });
    }
    render() {
        return (
            <nav className="navbar navbar-inverse">
                <div className="container-fluid">
                    <div className="navbar-header">
                        <Link className="navbar-brand" to="/">Cliphy</Link>
                    </div>
                    <div>
                        <ul className="nav navbar-nav">
                            <li>
                                <Link to="/">All Gifs</Link>
                            </li>
                            <li>
                                <Link to="/create">Create Gif</Link>
                            </li>
                        </ul>
                        <ul className="nav navbar-nav navbar-right">
                            <li>
                                {
                                    (isLoggedIn()) ? <button type="button" className="btn btn-raised btn-sm btn-default" onClick={this.uploadGif}>Upload Gif</button> : ''
                                }
                            </li>
                            <li>
                                {
                                    (isLoggedIn()) ?
                                        (
                                            <button type="button" className="btn btn-raised btn-sm btn-danger" onClick={() => logout()}>Log out </button>
                                        ) : (
                                            <button className="btn btn-sm btn-raised btn-default" onClick={() => login()}>Log In</button>
                                        )
                                }
                            </li>
                        </ul>
                    </div>
                </div>
            </nav>
        )
    }
}
export default Nav;

The cloudname_ and uploadpreset_ options are the only mandatory properties required to make uploads work, but we have set a few more options. Most important to note now is the tags, which we will use to work some magic. Now, login to the application and then click on the upload button to upload a new GIF file. Note that I have added some restrictions to the type of file that can be uploaded using the clientallowed_formats_ option of the upload widget. You can create a new upload preset from your Cloudinary dashboard. Do make sure it is an unsigned one. You also can check out your uploads from your dashboard. We have added a callback to our uploadWidget helper, which takes in the result object, so we can work with it.

云名称 _和上传预设_选项是使上传生效所需的唯一必需属性,但是我们还设置了一些其他选项。 现在最需要注意的是标签,我们将使用它们来处理一些魔术。 现在,登录到该应用程序,然后单击上载按钮以上载新的GIF文件。 请注意,我对使用上载小部件的client allowed_formats_选项可以上载的文件类型添加了一些限制。 您可以从Cloudinary仪表板创建一个新的上传预设。 请确保它是未签名的。 您也可以从信息中心查看上传的内容。 我们已经在我们的uploadWidget帮助器中添加了一个回调,该回调接受了result对象,因此我们可以使用它。

显示我们的GIF ( Displaying Our GIFs )

We have uploaded GIFs, but they are nowhere to be found on our dashboard. There are several ways this can be achieved. But since we are using React, we are in luck. Cloudinary provides a simple React component that is capable of handling the display of all our files. All we need to supply it is the publicId of our file on the cloud. Now remember that tag property we mentioned earlier during upload, here’s where we perform some magic with it. First off, let us install the Cloudinary React component.

我们已经上传了GIF,但在我们的信息中心找不到这些GIF。 有几种方法可以实现。 但是由于我们正在使用React,所以我们很幸运。 Cloudinary提供了一个简单的React组件,能够处理我们所有文件的显示。 我们需要提供的只是云上文件的publicId 。 现在,请记住我们在上载期间提到的tag属性,这是我们对其执行魔术的地方。 首先,让我们安装Cloudinary React组件。

npm install cloudinary-react

With this installed, we can retrieve all the images that we uploaded that bears the tag cliphy. There’s a simple way to do this - make a get request to a URL, such as this http://res.cloudinary.com/[CLOUD_NAME]/image/list/cliphy.json. Doing so returns many details about the GIF files we have uploaded, including the publicId of each of them. Another thing to note: the last part of the URL is the tag name we supplied during upload. Now let us modify components/Dashboard.js to look like this:

安装此程序后,我们可以检索上载带有cliphy标签的所有图像。 有一种简单的方法可以执行此操作-向URL发出get请求,例如http://res.cloudinary.com/[CLOUD_NAME]/image/list/cliphy.json. 这样做会返回有关我们上载的GIF文件的许多详细信息,包括每个文件的publicId 。 另一件事要注意:URL的最后一部分是我们在上传过程中提供的标签名称。 现在,让我们将components / Dashboard.js修改为如下所示:

import React, { Component } from 'react';
import { Link } from 'react-router';
import { CloudinaryContext, Transformation, Image } from "cloudinary-react";
import axios from 'axios';
import { isLoggedIn } from '../utils/AuthService';
import Nav from './Nav';
class Dashboard extends Component {
    state = {
        gifs: []
    };
    getGifs() {
        axios.get('http://res.cloudinary.com/[CLOUD_NAME]/image/list/cliphy.json')
            .then(res => {
                this.setState({ gifs: res.data.resources })
            });
    }
    componentDidMount() {
        this.getGifs();
    }
    render() {
        const { gifs } = this.state;
        return (
            <div>
                <Nav />
                <div className="row">
                    <h3 className="col-md-12"> The Dashboard</h3>
                    <CloudinaryContext cloudName="[CLOUD_NAME]">
                        {
                            gifs.map((data, index) => (
                                <div className="col-md-4 col-sm-6 col-xs-12" key={index}>
                                    <div className="panel panel-default">
                                        <div className="panel-body">
                                            <div className="embed-responsive embed-responsive-16by9">
                                                <Image className="img-responsive" publicId={data.public_id}></Image>
                                            </div>
                                        </div>
                                        <div className="panel-footer">
                                                                                   </div>
                                    </div>
                                </div>
                            ))
                        }
                    </CloudinaryContext>
                </div>
            </div>
        );
    }
}
export default Dashboard;

You should now see all the GIFs displayed in a very beautiful grid.

现在,您应该看到所有GIF都以非常漂亮的网格显示。

分享到社交媒体 ( Sharing to Social Media )

Now we will implement sharing on social media. First we install react-share component.

现在,我们将在社交媒体上实施共享。 首先,我们安装react-share组件。

npm install react-share

Now, copy and paste the following codes to the top of the components/Dashboard.js file.

现在,将以下代码复制并粘贴到components / Dashboard.js文件的顶部。

import { ShareButtons, generateShareIcon, ShareCounts } from 'react-share';
const {
    FacebookShareButton,
    TwitterShareButton,
  } = ShareButtons;

Now add the following piece of code within the div with class panel-footer.

现在使用类panel-footer在div中添加以下代码

Share on:
<TwitterShareButton className="label label-info" title={"Cliphy"} url={`http://res.cloudinary.com/[CLOUD_NAME]/image/upload/${data.public_id}.gif`}>
Twitter </TwitterShareButton>
<FacebookShareButton className="label label-default" url={`http://res.cloudinary.com/[CLOUD_NAME]/image/upload/${data.public_id}.gif`}>
  Facebook
</FacebookShareButton>

On reload, you should now have both share buttons for Facebook and Twitter.

重新加载后,您现在应该同时具有Facebook和Twitter的共享按钮。

制作自己的GIF ( Making our own GIFs )

It has been nice so far creating our own lovely GIF platform. But it would be even more awesome to be able to create our own GIFs from video files that we can then save to our computers. Let’s go ahead and build a GIF maker into our application and see how Cloudinary takes away much of the effort that would have been required to build this. Go ahead and open the empty components/Create.js file we created earlier and add the following piece of code to it.

到目前为止,创建我们自己的可爱GIF平台一直很好。 但是,能够从视频文件创建我们自己的GIF,然后将其保存到我们的计算机中,将更加出色。 让我们继续前进,在我们的应用程序中构建一个GIF生成器,看看Cloudinary如何消除构建它所需的大部分工作。 继续并打开我们之前创建的空的components / Create.js文件,并向其中添加以下代码。

import React, { Component } from 'react';
import { uploadWidget } from '../utils/WidgetHelper';
import Nav from './Nav';
class Create extends Component {
    state = {
        gifUrl: "",
        startTime: 0,
        endTime: 0,
        isResult: false,
    };
    setStartTime = (e) => {
        this.setState({ startTime: e.target.value });
    }
    setEndTime = (e) => {
        this.setState({ endTime: e.target.value });
    }
    createGif = () => {
        let cloudinarySettings = {
            cloud_name: '<CLOUD_NAME>',
            upload_preset: '<UPLOAD_PRESET>',
            sources: ['local'],
            client_allowed_formats: ['mp4', 'webm'],
            keep_widget_open: false,
            multiple: false,
            theme: 'minimal',
        }
        uploadWidget(cloudinarySettings, (res) => {
          if (res && res[0] !== undefined) {
                this.setState({ isResult: true });
                this.setGifString(res[0].public_id);
            }
            console.log(res);
        });
    }
    setGifString = (uploadedVideoId) => {
        this.setState({
            gifUrl: `http://res.cloudinary.com/[CLOUD_NAME]/video/upload${(this.state.startTime > 0 && this.state.endTime > 0) ? '/so_' + this.state.startTime + ',eo_' + this.state.endTime : ''}/${uploadedVideoId}.gif`
        });
    }
    render() {
        return (
            <div>
                <Nav />
                <div className="col-md-6 col-md-offset-3">
                    <div className="well well-sm">
                        <form className="form-horizontal">
                            <legend>Enter start and stop time for animation and hit upload to select file</legend>
                            <div className="form-group">
                                <label htmlFor="start" className="col-md-2 control-label">Start</label>
                                <div className="col-md-10">
                                    <input type="number" value={this.state.startTime} onChange={this.setStartTime} className="form-control" id="start"></input>
                                </div>
                            </div>
                            <div className="form-group">
                                <label htmlFor="end" className="col-md-2 control-label">End</label>
                                <div className="col-md-10">
                                    <input type="number" value={this.state.endTime} onChange={this.setEndTime} className="form-control" id="end"></input>
                                </div>
                            </div>
                            <div className="form-group">
                                <div className="col-sm-offset-2 col-sm-10">
                                    <button type="button" className="btn btn-raised btn-primary" onClick={this.createGif}>Create</button>
                                </div>
                            </div>
                        </form>
                    </div>
                    <div className="panel panel-default">
                        <div className="panel-body">
                            {
                                (this.state.isResult) ?
                                    <img className="img-responsive" src={this.state.gifUrl}></img> : <span className="label label-info">Kindly upload an mp4 video to create Gif</span>
                            }
                        </div>
                        <div className="panel-footer">
                        </div>
                    </div>
                </div >
            </div >
        );
    }
}
export default Create;

And just like that you have your own GIF maker. What’s going on here, why does it seem so simple and straightforward? Well, let me explain the various pieces of code I consider important. First, our reuse of uploadWidget from utils/WidgetHelper.js. We included it in our component and it is triggered when createGif is called. One notable change I’ve made in the options this time around is to only allow mp4 and webm formats. Go ahead and add other video formats if you feel the need to. Now take a look at this segment:

就像您拥有自己的GIF制造商一样。 这里发生了什么,为什么它看起来如此简单明了? 好吧,让我解释一下我认为重要的各种代码。 首先,我们重用utils / WidgetHelper.js中的uploadWidget。 我们将其包含在组件中,并在调用createGif时触发。 我这次在选项中所做的一项值得注意的更改是仅允许mp4webm格式。 如果需要,请继续添加其他视频格式。 现在看一下这一段:

setGifString = (uploadedVideoId) => {
        this.setState({
            gifUrl: `http://res.cloudinary.com/[CLOUD_NAME]/video/upload${(this.state.startTime > 0 && this.state.endTime > 0) ? '/so_' + this.state.startTime + ',eo_' + this.state.endTime : ''}/${uploadedVideoId}.gif`
        });
    }

There is just more magic going on here. Cloudinary is able to serve your videos as GIFs and all you have to do is append the extension .gif to the end of the resource url from Cloudinary. The so and eo parameters specify the start offset and end offset, meaning a specified start time to a stop time duration of the video will be converted to a GIF.

这里还有更多魔术。 Cloudinary能够将您的视频作为GIF格式提供,您所要做的就是将扩展名.gif附加到Cloudinary资源网址的末尾。 soeo参数指定开始偏移结束偏移 ,这意味着将指定的开始时间到视频的停止时间段转换为GIF。

结论 ( Conclusion )

Now you have a fully functional clone of your Giphy ready for a demo and your very own GIF maker to go with it. What more could you ask for? Cloudinary provides us with limitless possibilities with file management and a lot of other awesomeness if you’re working with media files. You should definitely go play with some more of the features that could be found in their documentation. The source code of the project is on GitHub. Let me know in the comments below if you have any questions or challenges.

现在,您已经拥有Giphy的功能齐全的克隆,可以进行演示了,您自己的GIF制造商也可以使用它。 你还能要求什么呢? 如果您正在使用媒体文件,Cloudinary为我们提供了无限的文件管理可能性,以及其他许多好处。 您绝对应该使用在其文档中可以找到的更多功能。 该项目的源代码在GitHub上 。 如果您有任何疑问或挑战,请在下面的评论中让我知道。

翻译自: https://scotch.io/tutorials/build-your-own-giphy-alternative-with-react

react 对象克隆

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值