精华内容
下载资源
问答
  • 1、为什么要用 React构建小程序react生态体系完善。 自Facebook在2013年5月开源React,经历了7年多的发展,react的社区生态体系非常庞大,若是使用react构建小程序,那么在小程序开发中可以充分利用 ...

    1、为什么要用 React 来构建小程序?

    • react生态体系完善

    自Facebook在2013年5月开源React,经历了7年多的发展,react的社区生态体系非常庞大,若是使用react来构建小程序,那么在小程序开发中可以充分利用 React 生态体系中大量的技术沉淀(比如:react-use、field-form)。

    • 更完整的 TypeScript 支持。

    (1)当然也可以用 TypeScript 去写现有的小程序,但是由于小程序的架构原因(在小程序中,模版层和逻辑层是分开的,分别运行在渲染线程和逻辑线程),模板层跟逻辑层有天然的割裂,即使在逻辑层使用了 TypeScript,在模板层也无法享受类型检查自动补全带来的便利。
    (2)引入 React 后,我们的代码全部运行在逻辑层中,可以全程静态类型护航,给你满满的安全感。

    2、使用react构建小程序的框架有哪些?

    1、nanachi(娜娜奇):去哪儿
    2、taro: 京东,taro1/2编译类型,taro3解释类型(类似微信kbone,模拟 Web 环境来对接前端生态)
    3、remax: 阿里蚂蚁金服
    4、Rax: 淘宝(业界唯一一个同时支持编译时和运行时引擎的小程序开发方案)

    编译时方案 运行时方案 编译时/运行时方案
    nanachi remax rax
    taro1/2 taro3

    推荐文章:在 2020 年,谈小程序框架该如何选择

    3、现有的方案

    静态编译
    目前社区中使用 React 构建小程序的方案大都使用静态编译的方式实现。
    所谓静态编译: 就是使用工具把代码语法分析一遍,把其中的 JSX 部分和逻辑部分抽取出来,分别生成小程序的静态模板和 小程序页面的定义。

    静态编译来构建小程序的缺陷:

    • js动态写法,无法编译,需规避很多的动态写法。

      因为语法分析是静态的,所以这些方案都会去限制一些动态的写法。另外正是因为 JavaScript 语言的动态性,要去做语法分析本身就是件很复杂的事情,所以这些方案实现起来往往也非常复杂。
      例子:含有动态语法无法正确编译的case
      在这里插入图片描述在这里插入图片描述

    • 运行时并没有 React 的存在,实际运行的是静态编译转换之后的小程序代码。

    4、remax的实现方案及工作原理

    Remax 让你可以使用真正的 React 去构建小程序,你可以把他理解成面向小程序的 React Native。

    先看下react的架构:

    • 最下面一层是 React 本身,上层的 ReactDOM 和 ReactNative等,也就是所说的render层。
    • Renderer层跟 React 之间通过渲染器(ReactReconciler )连接,渲染器的作用就是把React 的虚拟 DOM 映射到对应平台的真实元素上去,(譬如:react-dom 的作用就是把虚拟 DOM 映射到浏览器的真实 DOM 上)。
    • Remax实际上就是实现了一个面向小程序的渲染器,它把「虚拟 DOM」渲染到了小程序的视图层上。
      在这里插入图片描述

    问题:小程序没有DOM结构,remax是如何把虚拟DOM渲染到小程序的视图上的呢?
    》》》remax引入了Vnode

    remax工作流程:
    (1)在remax运行时,会通过渲染器将react中的组件渲染成Vnode结构,然后会调用节点上的 toJSON 方法,把这个 VNode 变成一个 JSON 对象,这个JOSN对象会被作为小程序页面page的data数据。

    Vnode是什么?
    VNode 就是 DOM 替代品,所以他长得也很像 DOM 元素,上面会有节点的类型(小程序中基础组件如:view、image、text),节点的属性和子节点,另外会有新增、删除和插入节点的方法.
    在这里插入图片描述

    import React from 'react';
    import { View, Text } from 'remax/alipay';
    
    const IndexPage = () => {
      return (
        <View className="greeting">
          <Text>Hello Remax</Text>
        </View>
      );
    };
    
    export default IndexPage;
    
    {
      "id": 0,
      "type": "root",
      "children": [
        {
          "id": 1,
          "type": "view",
          "props": {
            "className": "greeting"
          },
          "children": [
            {
              "id": 2,
              "type": "text",
              "props": {},
              "children": [
                {
                  "type": "plain-text",
                  "text": "Hello Remax"
                }
              ]
            }
          ]
        }
      ]
    }
    

    (2)remax会使用脚手架工具remax-cli 来构建我们的代码 ,这个构建过程会生成一个能遍历 data数据的模板。
    这个模板会先去遍历 data 根节点下的所有子元素,然后根据子元素的类型,使用其对应的模板来渲染这个节点。
    利用模板递归渲染 data 的过程,也就把 React 运行到了小程序中并渲染出了界面。

    // 模版
    <block a:for="{{root.children}}" a:key="{{item.id}}">
      <template is="{{'REMAX_TPL_' + item.type}}" data="{{item: item}}" />
    </block>
    // view类型模版
    <template name="REMAX_TPL_view">
      <view class="{{item.props['className']}}">
        <block a:for="{{item.children}}" key="{{item.id}}">
          <template is="{{'REMAX_TPL_' + item.type}}" data="{{item: item}}" />
        </block>
      </view>
    </template>
    
    <template name="REMAX_TPL_text">
      <text>
        <block a:for="{{item.children}}" key="{{item.id}}">
          <template is="{{'REMAX_TPL_' + item.type}}" data="{{item: item}}" />
        </block>
      </text>
    </template>
    
    <template name="REMAX_TPL_plain-text">
      <block>{{item.text}}</block>
    </template>
    

    小结:
    remax来构建小程序的思路,没有借助重新打造react的轮子以及使用静态编译分析语法的方式,将react编译成运行需要的小程序语言。
    remax的方案实现:
    我觉得主要还是借鉴了react的架构和RN的实现思路,从某种程度上来说,remax其实就是面向小程序的RN,只不过这个面向小程序的实现不能使用RN的渲染器,而是remax开发的面向小程序的渲染器。
    remax的亮点:

    • Vnode层的引入
    • Vnode转换成JSON的页面数据
    • 面向小程序的渲染器

    remax的工作原理:
    (1)引入了Vnode层,通过渲染器将react的虚拟DOM渲染成了Vnod结构树。
    (2)然后会调用节点上的 toJSON 方法,把这个 VNode 变成一个 JSON 对象。
    (3)这个JSON对象会作为小程序页面的Data数据。
    (4)在使用reamx-cli构建我们的代码时,构建过程会生成一个能遍历 data 的模板,在遍历的过程中,会根据元素的类型type去匹配对应的页面模版template,这个递归遍历的过程,通过使用对应的模版来承接data的数据展示,最终将data中数据展现在页面上。

    参考文章:
    1、Remax - 使用 React 开发小程序 - SEE Conf
    2、在小程序中实现动态模板 - Remax 实现原理
    3、Rax 小程序运行时方案解密与思考

    展开全文
  • https://remaxjs.org/quick-start/wechat

    https://remaxjs.org/quick-start/wechat

    展开全文
  • 介绍Remax 将 React 运行在小程序环境中,让你可以使用完整的 React 进行开发。类似于之前介绍过的AntMove,可以使用Remax把代码转换到多个小程序平台,提供完整的typeScript支持,无限制的使用React,可以当成是...

    介绍

    Remax 将 React 运行在小程序环境中,让你可以使用完整的 React 进行开发。类似于之前介绍过的AntMove,可以使用Remax把代码转换到多个小程序平台,提供完整的typeScript支持,无限制的使用React,可以当成是小程序的React Native!


    c1d95be4e961fc829310cedaca549f92.png

    Github坐标

    https://github.com/remaxjs/remax

    相关特性

    下面是来自官方文档的介绍:

    Remax 将 React 运行在小程序环境中,让你可以使用完整的 React 进行开发。

    • 真正的 React - 不同于静态编译的方案,在 Remax 中使用 React 没有任何限制,包括 React Hooks。你可以把 Remax 理解为针对小程序的 React Native。
    • 多端支持 - 使用 Remax 把代码转换到多个小程序平台。
    • TypeScript - 完整的 TypeScript 支持,给你满满的安全感。

    同时在文档中也提到了为什么要用React来构建小程序,感兴趣的可以移步官网文档!


    633745c6933749c0b230794af6a92860.png

    快速开始

    官方文档提供了微信和支付宝的入门小程序项目,我们一起来看一看:

    • 支付宝小程序

    1、创建项目

    $ npx degit remaxjs/template-alipay my-app$ cd my-app && npm install

    2、运行项目

    npm run dev

    3、打开支付宝小程序开发者工具,选中项目 dist 目录,你将看到


    343cd29b7c958cff2ee60c603756ff97.png

    4、项目结构

    dist 为编译后的文件目录。src 为源文件目录。app.js 即小程序 App 方法,可以在 class 内定义对应的属性


    7a8349ed54621b05270f470b0fe144e7.png

    f3d05b9341b52c306f88838ffe2c4efe.png

    app.css 全局样式文件,app.config.js 为小程序全局配置文件,对应 app.json,pages 存放项目页面,pages/index/index.js 页面文件,对应小程序 Page 方法


    b91f3bb054a3359368cfb4446f7950f2.png

    默认导出的的 React 组件就是当前的页面,关于生命周期的使用方式参考官网文档中的生命周期指南!

    • 微信小程序

    微信小程序是类似的,再次就不再赘述!


    组件

    Remax 用驼峰的方式来命令小程序组件,如:

    import { View, Text, Image, ... } from 'remax/wechat'

    • Props

    Remax 遵循 React 规范来命名小程序属性,如: Remax


    对应微信小程序:

    对应支付宝小程序:


    e9f5152098c203ad3b25c41499792150.png

    样式

    Remax 默认支持 css/less/sass/stylus,安装你需要的样式,即可使用。如:

     npm install less # less 用户 npm install node-sass # sass 用户

    import './index.css';import './index.less';import './index.scss';

    Remax 会自动把 px 转换成小程序 rpx:

    .view { height: 16px;}.view { height: 16rpx;}

    如果你不想转换 px ,就写成 PX,如:

    .view { height: 16PX:}

    Remax 同时也支持 Css Modules


    e033930aedd1ada7138021eaf48735db.png

    生命周期

    Remax 在 component class 中增加了对生命周期的支持,如:

    export default class Page extends React.Component { onShow() { console.log('on show'); } onHide() { console.log('on hide'); } ...}

    同样也支持 React Hooks

    import { useShow, useHide } from 'remax';import { View } from 'remax/wechat';export default () => { useShow(() => { console.log('onShow'); }); useHide(() => { console.log('onHide'); }); return view;};

    8b1fe7937b16068c51536b562dc757da.png

    小程序 API

    Remax 提供原生小程序 API 支持,如;

    import { navigateTo, requestPayment, ... } from 'remax/wechat'

    拥有事件回调(success,fail)的 API,Remax 还提供 Promise 支持,如:

    import { requestPayment } from 'remax/wechat';requestPayment(params).then(res => { console.log(res);});

    001140fac8c0e0736d204f35324855d4.png

    页面参数

    Remax 将页面参数通过 props 传递给页面组件,如:

    export default (props) => { // 页面参数 console.log(props.location.query); ...}

    你也可以通过小程序原生的方式获取参数(通常在 onLoad 方法里获取),包括场景值也是。

    平台

    Remax 目前支持的平台

    • 微信小程序: wechat
    • 支付宝小程序: alipay

    关于跨平台相关的可以参照官网文档的高级指南部分


    38c333512bdb393cff07401393a076d1.png

    Typescript

    Remax 默认支持用 TypeScript 开发。作者亦提供了 TypeScript 模板帮助你快速创建项目。

    • 微信
    $ npx degit remaxjs/template-wechat-typescript my-app$ cd my-app
    • 支付宝
    $ npx degit remaxjs/template-alipay-typescript my-app$ cd my-app
    • 跨平台
    $ npx degit remaxjs/template-universe-typescript my-app$ cd my-app

    63dd921147feb3da4ef1e7717ee1d089.png

    以上都只是依据文档对其进行简单的介绍,具体的还包括跨平台开发配置、状态共享以及原生混合开发等,感兴趣的同学可以尝试上手!

    总结

    当下软件开发包括很多种类,小程序也是其中重要的一环,目前有很多类似于Remax的框架供我们选择,不同的框架解决的问题大致类似,但是编写代码的方式可能每一个框架适合不同的人来写,像Remax和Taro这样的就比较适合熟悉React的开发者使用,而向uni-app或者还有其他的框架或许更适合Vue的开发者,也有一些类似于原生的,对于热爱学习的小伙伴可以选择不同的解决方案来学习!

    展开全文
  • 学习一次,随处写使用真正的React构建小程序 Remax将React运行在小程序环境中,让你可以使用完整的React进行小程序开发。 真正的React-静态静态编译的方案,在Remax中使用React没有任何限制,包括React Hooks。你...
  • 它在生产模式下正确捆绑了React,并优化了构建以获得最佳性能。 生成被最小化,并且文件名包括哈希值。 您的应用已准备好进行部署! 有关更多信息,请参见关于的部分。 yarn eject 注意:这是单向操作。 eject ...
  • 使用Babel构建可测试的React应用程序的最小框架。 设计目标 使用更少的工具(不要使用yeoman,gulp,bower等) 带Webpack和热加载器的Babel 6 使用模拟出的DOM进行快速测试 导入CSS文件作为类名 分开的组件 没有...
  • react.js做小程序In this tutorial, I will guide you to build your own group chat application using React, React Router, and CometChat Pro. Yes, rather than roll out our own server, we will instead use ...

    react.js做小程序

    In this tutorial, I will guide you to build your own group chat application using React, React Router, and CometChat Pro. Yes, rather than roll out our own server, we will instead use CometChat Pro to handle the real-time sending and receiving of chat messages.

    在本教程中,我将指导您使用React,React Router和CometChat Pro构建自己的群聊应用程序。 是的,我们不会使用自己的服务器,而是使用CometChat Pro来处理聊天消息的实时发送和接收。

    When you’re done, you should have a functional chat application that looks something like this (of course, you’re welcome to tweak and experiment with things as you go along):

    完成后,您应该拥有一个类似以下功能的聊天应用程序(当然,欢迎您在进行过程中进行调整和试验):

    I have structured this tutorial as a series of steps to make it easy to follow along. If you’d just like to check out the code, click here.

    我将本教程分为一系列步骤,以使其易于学习。 如果您只想查看代码, 请点击此处

    设置项目 (Setting up the project)

    Before we go too far, we must first set up our React project. To do this, we’ll use a lesser-known gem called Create React App.

    在我们走得太远之前,我们必须首先设置我们的React项目。 为此,我们将使用一个鲜为人知的称为Create React App的gem。

    The best thing? Because you have npm installed, you can use npx to install and run create-react-app in one step:

    最好的东西? 由于已安装npm,因此可以使用npx一步安装并运行create-react-app:

    npx create-react-app chatapp // note: npm v5.2+

    npx create-react-app chatapp // note: npm v5.2+

    After running this command, a new folder called “chatapp” will be created with the following structure:

    运行此命令后,将使用以下结构创建一个名为“ chatapp”的新文件夹:

    In addition, to React, we will also need to install React Router and CometChat Pro SDK. To do this, head to the chatapp directory and run:

    此外,对于React,我们还需要安装React Router和CometChat Pro SDK。 为此,请转到chatapp目录并运行:

    npm install react-router-dom @cometchat-pro/chat --save

    npm install react-router-dom @cometchat-pro/chat --save

    添加React路由器 (Add React Router)

    In the end, our application will have two pages — one called Login where the user will log in, and another called Groupchat where we will render the chat room. We will use React Router to route users to the page they need.

    最后,我们的应用程序将有两个页面-一个页面称为Login ,用户将在该页面Login ;另一个页面名为Groupchat ,在此Groupchat ,我们将提供聊天室。 我们将使用React Router将用户路由到他们需要的页面。

    To setup React Router, we must first import the Router wrapper component in our index.js file. I call it a wrapper component because we wrap our App inside the Router component.

    要设置React Router,我们必须首先在index.js文件中导入Router 包装器组件。 我将其称为包装器组件,因为我们将App封装在Router组件中。

    Replace index.js with this snippet:

    使用以下代码段替换index.js:

    import React from 'react';
    import { BrowserRouter as Router } from 'react-router-dom'; // added
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    ReactDOM.render(
      <Router>
        <App />
      </Router>
      , document.getElementById('root'));

    index.js is the entry point for our application. Its only real job is to render our React application. Most of our “real” logic happens in a file called App.js, which we will modify next.

    index.js是我们应用程序的入口点。 唯一真正的工作就是渲染我们的React应用程序。 我们大多数的“真实”逻辑都发生在名为App.js的文件中,接下来我们将对其进行修改。

    In App.js, we must import additional React Router dependencies which will enable us to render different components depending on what route the user has loaded. For example, if the user goes to the “/login” route, we should render the Login component. Likewise, if the user goes to the “/chat” route, we should render the Groupchat component:

    在App.js中,我们必须导入其他React Router依赖关系,这将使我们能够根据用户加载的路线来呈现不同的组件。 例如,如果用户转到“ / login”路线,则应呈现“登录”组件。 同样,如果用户转到“ / chat”路线,则应呈现Groupchat组件:

    import React, { Component } from "react";
    import { Route, Redirect, Switch } from "react-router-dom";
    import "./App.css";
    // the below components will be created shortly
    import Login from "./components/Login";
    import Groupchat from "./components/Groupchat";
    class App extends Component {
      constructor(props) {
        super(props);
      }
    render() {
        return (
          <Switch>
            <Redirect exact from="/" to="/login" />
            <Route path="/login" component={Login} />
            <Route path="/chat" component={Groupchat} />
          </Switch>
        );
      }
    }
    export default App;

    If you try to run this code it will definitely throw some errors because we haven’t made the Login and Groupchat components. Let’s do that now.

    如果您尝试运行此代码,则肯定会引发一些错误,因为我们尚未创建LoginGroupchat组件。 现在开始吧。

    创建登录组件 (Create the Login component)

    To keep our project nice and tidy, create a folder called components to hold our custom components.

    为了使我们的项目保持整洁,请创建一个名为components的文件夹来保存我们的自定义组件。

    Then, in that newly-created folder, create a file called Login.js with the following code:

    然后,在该新创建的文件夹中,使用以下代码创建一个名为Login.js的文件:

    import React from "react";
    class Login extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
        };
      }
      render() {
        return ( 
          <div className="App">
            <h1>Login</h1>
          </div>
        );
      }
    }
    export default Login;

    All we’re doing here is exporting a component with the heading text, “Login”. We’ll flesh this component out soon but for right now, we are merely creating boilerplate.

    我们在这里所做的就是导出带有标题文本“ Login”的组件。 我们将尽快充实此组件,但就目前而言,我们仅创建样板。

    创建Groupchat组件 (Create the Groupchat component)

    In the same components folder, create a new component called Groupchat.js:

    在相同的components文件夹中,创建一个名为Groupchat.js的新组件:

    import React from "react";
    class Groupchat extends React.Component {
      constructor(props) {
        super(props);
      }
      render() {
        return <div className="chatWindow" />;
      }
    }
    export default Groupchat;

    As we progress through the tutorial, we will develop this humble component into the core of our chat application.

    在学习本教程的过程中,我们将把这个不起眼的组件开发成聊天应用程序的核心。

    With the Groupchat and Login components in place, you should be able to run the application without an error. Open the app on localhost and navigate to localhost:3000/login and then localhost:3000/chat to see the components in action.

    有了GroupchatLogin组件后,您应该能够运行该应用程序而不会出现错误。 在localhost上打开应用程序,然后导航到localhost:3000 / login,然后导航到localhost:3000 / chat以查看正在使用的组件。

    创建CometChat APP ID和API密钥 (Create the CometChat APP ID and API key)

    Like I mentioned at the beginning of the tutorial, we won’t be rolling out our own server in this tutorial. Instead, we’ll be using a hosted service of CometChat Pro.

    就像我在本教程开始时提到的那样,我们不会在本教程中推出自己的服务器。 相反,我们将使用CometChat Pro的托管服务。

    Before we can connect to CometChat, we must first create a CometChat application from the dashboard:

    在连接到CometChat之前,我们必须首先从仪表板创建CometChat应用程序:

    Once your application has been created, hit “Explore” then head to the “API Keys” tab:

    创建应用程序后,点击“浏览”,然后转到“ API密钥”选项卡:

    Click “Create API key” and fill in the form, choosing Auth Only scope. From the table, you can note your application ID and application key, we’ll need these shortly.

    单击“创建API密钥”并填写表格,选择“仅验证”范围。 在表格中,您可以记下您的应用程序ID和应用程序密钥,我们很快将需要它们。

    创建CometChat组ID (Create the CometChat group ID)

    While we have the dashboard open, let’s also create a group. Normally you’d do this with code (for example, you might allow the user to create a custom chat group for their team or project through your app) but for learning and testing, the dashboard is fine.

    打开仪表板后,我们还要创建一个group 。 通常,您可以使用代码来执行此操作(例如,您可以允许用户通过您的应用程序为其团队或项目创建自定义聊天组),但是对于学习和测试而言,仪表板很好。

    Head to the “Groups” tab and create a new group called testgroup:

    转到“组”选项卡并创建一个名为testgroup的新组:

    Like last time, you’ll be taken back to a table where you can note the group ID:

    与上次一样,您将被带回到一个表中,您可以在其中记录组ID:

    Take note as we’ll need this in the next step.

    请注意,因为下一步将需要它。

    创建配置文件 (Create the configuration file)

    To make it easy to reference our configuration, create a new file called config.js and paste your credentials:

    为了便于参考我们的配置,请创建一个名为config.js的新文件并粘贴您的凭据:

    export default {
      appId: "", //Enter your App ID
      apiKey: "", //Enter your API KEY
      GUID: "", // Enter your group UID
    };

    You can now close the dashboard. Once you setup CometChat, all interaction happens through code.

    现在,您可以关闭仪表板。 设置CometChat后,所有交互都将通过代码进行。

    创建一个CometChat Manager类 (Create a CometChat Manager class)

    One of the beautiful things about React is that it lends itself to a separation of concerns. Our components can focus purely on presentation while we can create other modules to handle things like data fetching and state management.

    React的美丽之处之一是它使关注点分离。 我们的组件可以完全专注于表示,而我们可以创建其他模块来处理诸如数据获取和状态管理之类的事情。

    To really take advantage of this, let’s create a new folder called “lib” and in that new folder, a file called chat.js. This is where all of our interaction with CometChat will take place:

    为了真正利用这一点,让我们创建一个名为“ lib”的新文件夹,并在该新文件夹中创建一个名为chat.js的文件。 这是我们与CometChat进行所有互动的地方:

    import { CometChat } from "@cometchat-pro/chat";
    import config from "../config";
    export default class CCManager {
      static LISTENER_KEY_MESSAGE = "msglistener";
      static appId = config.appId;
      static apiKey = config.apiKey;
      static LISTENER_KEY_GROUP = "grouplistener";
      static init() {
        return CometChat.init(CCManager.appId);
      }
      static getTextMessage(uid, text, msgType) {
        if (msgType === "user") {
          return new CometChat.TextMessage(
            uid,
            text,
            CometChat.MESSAGE_TYPE.TEXT,
            CometChat.RECEIVER_TYPE.USER
          );
        } else {
          return new CometChat.TextMessage(
            uid,
            text,
            CometChat.MESSAGE_TYPE.TEXT,
            CometChat.RECEIVER_TYPE.GROUP
          );
        }
      }
      static getLoggedinUser() {
        return CometChat.getLoggedinUser();
      }
      static login(UID) {
        return CometChat.login(UID, this.apiKey);
      }
      static getGroupMessages(GUID, callback, limit = 30) {
        const messagesRequest = new CometChat.MessagesRequestBuilder()
          .setGUID(GUID)
          .setLimit(limit)
          .build();
        callback();
        return messagesRequest.fetchPrevious();
      }
      static sendGroupMessage(UID, message) {
        const textMessage = this.getTextMessage(UID, message, "group");
        return CometChat.sendMessage(textMessage);
      }
      static joinGroup(GUID) {
        return CometChat.joinGroup(GUID, CometChat.GROUP_TYPE.PUBLIC, "");
      }
      static addMessageListener(callback) {
        CometChat.addMessageListener(
          this.LISTENER_KEY_MESSAGE,
          new CometChat.MessageListener({
            onTextMessageReceived: textMessage => {
              callback(textMessage);
            }
          })
        );
      }
    }

    Aside from allowing us to create a separation of concerns, presenting the code like this also makes it easier to digest.

    除了允许我们创建关注点分离之外,像这样显示代码也使摘要更容易理解。

    Let me explain some important parts of this module, starting from the top:

    让我从顶部开始解释该模块的一些重要部分:

    • LISTENER_KEY_MESSAGE – This is required by the message listener.

      LISTENER_KEY_MESSAGE –这是消息侦听LISTENER_KEY_MESSAGE所必需的。

    • init() – This is required to be called only once throughout the lifecycle of the application, it calls the CometChat init method with the appID.

      init() –在应用程序的整个生命周期中仅需调用一次,它使用appID调用CometChat init方法。

    • getTextMessage(uid, text, msgType) – it creates the message object based on CometChat.TextMessagemethod, it accepts the UID (GUID in our case) and the text message to send.

      getTextMessage(uid, text, msgType) –它基于CometChat.TextMessage方法创建消息对象,它接受UID(在本例中为GUID)和要发送的文本消息。

    • getLoggedInUser() – it’s used to get the currently logged in user.

      getLoggedInUser() –用于获取当前登录的用户。

    • login() – it’s used to log in a user based on the CometChat.login method, it takes in the UID (GUID in our case) and the apiKey.

      login() –用于基于CometChat.login方法登录用户,它接受UID(在本例中为GUID)和apiKey。

    • getGroupMessages(GUID, callback, limit = 30) – this is used to get the previous group messages from CometChat using the CometChat.MessagesRequestBuilder() method that takes in the GUID and limit as parameters.

      getGroupMessages(GUID, callback, limit = 30) –用于使用CometChat.MessagesRequestBuilder()方法从CometChat获取先前的组消息,该方法接受GUID和limit作为参数。

    • sendGroupMessage(UID, message)– this is used to send messages using the CometChat.sendMessage() method and it accepts the GUID and message as parameters.

      sendGroupMessage(UID, message) –用于使用CometChat.sendMessage()方法发送消息,并且接受GUID和消息作为参数。

    • joinGroup(GUID) – It’s used to join a chosen group using a GUID.

      joinGroup(GUID) –用于使用GUID加入选定的组。

    • addMessageListener(callback) – Uses the CometChat.addMessageListener() to listen to messages (did I mention this is called in real-time?), it requires the LISTENER_KEY_MESSAGE as a parameter and also a callback that is called when a message is received.

      addMessageListener(callback) –使用CometChat.addMessageListener()侦听消息(我是否提到过实时调用此消息?),它需要LISTENER_KEY_MESSAGE作为参数,还需要在收到消息时调用的回调。

    There’s nothing specific to this application here. You could well take this module, expand it if needed, and import it into another project. Generally, though, this is just a thin wrapper around the SDK.

    这里没有特定于此应用程序的内容。 您可以采用此模块,如果需要将其扩展,然后将其导入另一个项目。 通常,这只是SDK的一个薄包装。

    更新登录组件 (Update the login component)

    With all our configuration and chat code in place, we can now rapidly build out the UI starting with the Login component.

    有了我们所有的配置和聊天代码,我们现在可以从Login组件开始快速构建UI。

    Just to remind you, this is what the Login component will look like:

    提醒您,这是Login组件的外观:

    As you can see, its main function is to ask the user for their name. Once a name is supplied, we render the Groupchat component.

    如您所见,它的主要功能是询问用户的姓名。 提供名称后,我们将呈现Groupchat组件。

    Replace Login.js with:

    Login.js替换为:

    import React from "react";
    import { Redirect } from "react-router-dom";
    import chat from "../lib/chat";
    import spinner from "../logo.svg";
    class Login extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          username: "",
          isAuthenticated: false,
          user: null,
          isSubmitting: false,
          errorMessage: ""
        };
      }
      onSubmit = e => {
        if (this.state.username !== "") {
          e.preventDefault();
          this.login();
        }
      };
      login = () => {
        this.toggleIsSubmitting();
        chat
        .login(this.state.username)
        .then(user => {
          this.setState({
            user,
            isAuthenticated: true
          });
        })
        .catch(error => {
          this.setState({
            errorMessage: "Please enter a valid username"
          });
          this.toggleIsSubmitting();
          console.log(error);
        });
      };
      toggleIsSubmitting = () => {
        this.setState(prevState => ({
          isSubmitting: !prevState.isSubmitting
        }));
      };
      handleInputChange = e => {
        this.setState({
          username: e.target.value
        });
      };
      render() {
        if (this.state.isAuthenticated) {
          return (
            <Redirect
              to={{
                pathname: "/chat",
                state: { user: this.state.user }
              }}
            />
          );
        }
        return (
          <div className="App">
            <h1>COMETCHAT</h1>
            <p>Create an account through your CometChat dashboard or login with one of our test users, superhero1, superhero2, etc.</p>
            <form className="form" onSubmit={this.onSubmit}>
              <input onChange={this.handleInputChange} type="text" />
              <span className="error">{this.state.errorMessage}</span>
              {this.state.isSubmitting ? (
                <img src={spinner} alt="Spinner component" className="App-logo" />
              ) : (
                <input
                  type="submit"
                  disabled={this.state.username === ""}
                  value="LOGIN"
                />
              )}
            </form>
          </div>
        );
      }
    }
    export default Login;

    Aside from the presentational HTML, most code here is dedicated to handling a React form.

    除了演示HTML之外,这里的大多数代码都专用于处理React表单

    更新Groupchat组件 (Update the Groupchat component)

    The Groupchat component has a lot more responsibility than the Login component. As a quick reminder, this is what it will look like:

    Groupchat组件比Login组件承担更多的责任。 快速提醒一下,这是这样的:

    For the most part, the Groupchat component’s job is to bridge the chat lib module and the UI we’ll present to the user. For example, when a user sends a message, we call chat.sendMessage and as new messages trickle in, a callback function is called:

    在大多数情况下, Groupchat组件的工作是桥接chat lib模块和我们将提供给用户的UI。 例如,当用户发送消息时,我们称为chat.sendMessage ,随着新消息的滴入,回调函数将被调用:

    import React from "react";
    import { Redirect } from "react-router-dom";
    import chat from "../lib/chat";
    import config from "../config";
    class Groupchat extends React.Component {
      constructor(props) {
        super(props);
    this.state = {
          receiverID: "",
          messageText: null,
          groupMessage: [],
          user: {},
          isAuthenticated: true
        };
    this.GUID = config.GUID;
      }
    sendMessage = () => {
        chat.sendGroupMessage(this.GUID, this.state.messageText).then(
          message => {
            console.log("Message sent successfully:", message);
            this.setState({ messageText: null });
          },
          error => {
            if (error.code === "ERR_NOT_A_MEMBER") {
              chat.joinGroup(this.GUID).then(response => {
                this.sendMessage();
              });
            }
          }
        );
      };
    scrollToBottom = () => {
        const chat = document.getElementById("chatList");
        chat.scrollTop = chat.scrollHeight;
      };
    handleSubmit = event => {
        event.preventDefault();
        this.sendMessage();
        event.target.reset();
      };
    handleChange = event => {
        this.setState({ messageText: event.target.value });
      };
    getUser = () => {
        chat
          .getLoggedinUser()
          .then(user => {
            console.log("user details:", { user });
            this.setState({ user });
          })
          .catch(({ error }) => {
            if (error.code === "USER_NOT_LOGED_IN") {
              this.setState({
                isAuthenticated: false
              });
            }
          });
      };
    messageListener = () => {
        chat.addMessageListener((data, error) => {
          if (error) return console.log(`error: ${error}`);
          this.setState(
            prevState => ({
              groupMessage: [...prevState.groupMessage, data]
            }),
            () => {
              this.scrollToBottom();
            }
          );
        });
      };
    componentDidMount() {
        this.getUser();
        this.messageListener();
        // chat.joinGroup(this.GUID)
      }
    render() {
        const { isAuthenticated } = this.state;
        if (!isAuthenticated) {
          return <Redirect to="/" />;
        }
        return (
          <div className="chatWindow">
            <ul className="chat" id="chatList">
              {this.state.groupMessage.map(data => (
                <div key={data.id}>
                  {this.state.user.uid === data.sender.uid ? (
                    <li className="self">
                      <div className="msg">
                        <p>{data.sender.uid}</p>
                        <div className="message"> {data.data.text}</div>
                      </div>
                    </li>
                  ) : (
                    <li className="other">
                      <div className="msg">
                        <p>{data.sender.uid}</p>
                       <div className="message"> {data.data.text} </div>
                      </div>
                    </li>
                  )}
                </div>
              ))}
            </ul>
            <div className="chatInputWrapper">
              <form onSubmit={this.handleSubmit}>
                <input
                  className="textarea input"
                  type="text"
                  placeholder="Enter your message..."
                  onChange={this.handleChange}
                />
              </form>
            </div>
          </div>
        );
      }
    }
    export default Groupchat;<

    There’s a lot to digest here, so let’s break the important parts down:

    这里有很多要消化的东西,所以让我们分解重要的部分:

    • sendMessage() – This function handles sending a message to the group, passing the GUID and the text message that is stored is in the component’s state. If the user is not part of the group we then make a request to join the group and then call the sendMessage function again.

      sendMessage() –此函数处理将消息发送到组,传递GUID,并且所存储的文本消息处于组件状态。 如果该用户不属于该组,则我们将请求加入该组,然后再次调用sendMessage函数。

    • scrollToBottom() – This function will be used as a callback function for the message listener, it just makes sure that the latest messages are shown in the chat list.

      scrollToBottom() –此函数将用作消息侦听器的回调函数,它只是确保最新消息显示在聊天列表中。

    • handleSubmit() – This calls the sendMessage function.

      handleSubmit() –调用sendMessage函数。

    • getUser() – This calls the chat.getLoggedInUser() method and stores the user object in the component’s state.

      getUser() –调用chat.getLoggedInUser()方法并将用户对象存储在组件的状态中。

    • messageListener() – This calls the chat.addMessageListener() function and appends every new message received to the groupMessage array which is stored in the component’s state and rendered in the app.

      messageListener() –调用chat.addMessageListener()函数,并将接收到的groupMessage追加到groupMessage数组中,该数组存储在组件状态中并在应用程序中呈现。

    • componentDidMount() – This calls the getUser and messageListener functions.

      componentDidMount() –这将调用getUser和messageListener函数。

    Finally, we render a class depending on if the message is ours or someone else’s. This way, we can apply different styles which is the topic of the next section.

    最后,我们根据消息是我们的消息还是其他人的消息来渲染类。 这样,我们可以应用不同的样式,这是下一部分的主题。

    更新样式 (Update the styles)

    If you were to run the application now, it would work but with no CSS to speak of thus far, it would look quite uh, odd.

    如果您现在要运行该应用程序,它将可以运行,但是到目前为止还没有CSS可以说,它看起来很奇怪。

    This isn’t a tutorial about CSS so I won’t explain it in any detail, but to help you follow along, you can paste the following into your App.css file (you will have one already because it was generated by create-react-app earlier):

    这不是一本关于CSS的教程,因此我将不做任何详细解释,但是为了帮助您继续学习,您可以将以下内容粘贴到您的App.css文件中(您已经有了一个,因为它是由create-react-app之前):

    .App {
      text-align: center;
      display: flex;
      width: 100%;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      height: 50vh;
    }
    .App p{
      font-size: 12px;
      width: 50%;
    }
    .App-logo {
      animation: App-logo-spin infinite 0.5s linear;
      height: 10vmin;
    }
    .form {
      display: flex;
      flex-direction: column;
    }
    .form input[type="text"] {
      width: 300px;
      height: 30px;
      margin-bottom: 10px;
    }
    .form input[type="submit"] {
      padding: 5px;
      height: 30px;
      border: none;
      background-color: #187dbc;
      color: #fff;
    }
    .form input[type="submit"]:hover {
      border: #fff;
      cursor: pointer;
      background-color: #000;
      color: #fff;
    }
    .error{
      color: red;
      font-size: 10px;
      text-align: center;
    }
    @keyframes App-logo-spin {
      from {
        transform: rotate(0deg);
      }
      to {
        transform: rotate(360deg);
      }
    }
    .message {
      font-size: 15px !important;
    }
    body {
      background-color: #f5f5f5;
      font: 600 18px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Lato,
        Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
      color: #4b4b4b;
    }
    .container {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      grid-template-rows: repeat(1, 50px);
      grid-gap: 3px;
      margin-top: 15px;
    }
    .group {
      background: #4eb5e5;
      grid-column-start: 1;
      grid-column-end: 2;
      grid-row-start: 1;
      grid-row-end: 190;
      border-radius: 5px;
    }
    .chatWindow {
      display: grid;
      grid-column-start: 2;
      grid-column-end: 9;
      grid-row-start: 1;
      grid-row-end: 190;
      background: rgb(233, 229, 229);
      border-radius: 5px;
    }
    .chatInputWrapper {
      display: grid;
      grid-row-start: 190;
      grid-row-end: 190;
    }
    ::-webkit-scrollbar {
      display: none;
    }
    /* M E S S A G E S */
    .chat {
      list-style: none;
      background: none;
      margin: 0;
      padding: 0 0 50px 0;
      margin-top: 60px;
      margin-bottom: 10px;
      max-height: 400px;
      overflow: scroll;
      scroll-behavior: smooth;
    }
    .chat li {
      padding: 0.5rem;
      overflow: hidden;
      display: flex;
    }
    .chat .avatar {
      position: relative;
      display: block;
      z-index: 2;
    }
    .chat .avatar img {
      background-color: rgba(255, 255, 255, 0.9);
      -webkit-touch-callout: none;
      -webkit-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
    }
    .chat .uid img {
      background-color: rgba(255, 255, 255, 0.9);
      -webkit-touch-callout: none;
      -webkit-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
    }
    .chat .day {
      position: relative;
      display: block;
      text-align: center;
      color: #c0c0c0;
      height: 20px;
      text-shadow: 7px 0px 0px #e5e5e5, 6px 0px 0px #e5e5e5, 5px 0px 0px #e5e5e5,
        4px 0px 0px #e5e5e5, 3px 0px 0px #e5e5e5, 2px 0px 0px #e5e5e5,
        1px 0px 0px #e5e5e5, 1px 0px 0px #e5e5e5, 0px 0px 0px #e5e5e5,
        -1px 0px 0px #e5e5e5, -2px 0px 0px #e5e5e5, -3px 0px 0px #e5e5e5,
        -4px 0px 0px #e5e5e5, -5px 0px 0px #e5e5e5, -6px 0px 0px #e5e5e5,
        -7px 0px 0px #e5e5e5;
      box-shadow: inset 20px 0px 0px #e5e5e5, inset -20px 0px 0px #e5e5e5,
        inset 0px -2px 0px #d7d7d7;
      line-height: 38px;
      margin-top: 5px;
      margin-bottom: 20px;
      cursor: default;
      -webkit-touch-callout: none;
      -webkit-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
    }
    .other .msg {
      order: 1;
      border-top-left-radius: 0px;
      box-shadow: -1px 2px 0px #d4d4d4;
    }
    .other:before {
      content: "";
      position: relative;
      top: 0px;
      right: 0px;
      left: 40px;
      width: 0px;
      height: 0px;
      border: 5px solid #fff;
      border-left-color: transparent;
      border-bottom-color: transparent;
    }
    .self {
      justify-content: flex-end;
      align-items: flex-end;
    }
    .self .msg {
      order: 1;
      border-bottom-right-radius: 0px;
      box-shadow: 1px 2px 0px #d4d4d4;
    }
    .self .avatar {
      order: 2;
    }
    .self .avatar:after {
      content: "";
      position: relative;
      display: inline-block;
      bottom: 19px;
      right: 0px;
      width: 0px;
      height: 0px;
      border: 5px solid #fff;
      border-right-color: transparent;
      border-top-color: transparent;
      box-shadow: 0px 2px 0px #d4d4d4;
    }
    .msg {
      background: white;
      min-width: fit-content;
      padding: 10px;
      border-radius: 10px;
      box-shadow: 0px 2px 0px rgba(0, 0, 0, 0.07);
    }
    .msg p {
      font-size: 0.8rem;
      margin: 0 0 0.2rem 0;
      color: rgb(81, 84, 255);
    }
    .msg img {
      position: relative;
      display: block;
      width: 450px;
      border-radius: 5px;
      box-shadow: 0px 0px 3px #eee;
      transition: all 0.4s cubic-bezier(0.565, -0.26, 0.255, 1.41);
      cursor: default;
      -webkit-touch-callout: none;
      -webkit-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
    }
    @media screen and (max-width: 800px) {
      .msg img {
        width: 300px;
      }
    }
    @media screen and (max-width: 550px) {
      .msg img {
        width: 200px;
      }
    }
    .msg time {
      font-size: 0.7rem;
      color: #ccc;
      margin-top: 3px;
      float: right;
      cursor: default;
      -webkit-touch-callout: none;
      -webkit-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
    }
    .msg time:before {
      content: " ";
      color: #ddd;
      font-family: FontAwesome;
      display: inline-block;
      margin-right: 4px;
    }
    ::-webkit-scrollbar {
      min-width: 12px;
      width: 12px;
      max-width: 12px;
      min-height: 12px;
      height: 12px;
      max-height: 12px;
      background: #e5e5e5;
    }
    ::-webkit-scrollbar-thumb {
      background: rgb(48, 87, 158);
      border: none;
      border-radius: 100px;
      border: solid 3px #e5e5e5;
      box-shadow: inset 0px 0px 3px #999;
    }
    ::-webkit-scrollbar-thumb:hover {
      background: #b0b0b0;
      box-shadow: inset 0px 0px 3px #888;
    }
    ::-webkit-scrollbar-thumb:active {
      background: #aaa;
      box-shadow: inset 0px 0px 3px #7f7f7f;
    }
    ::-webkit-scrollbar-button {
      display: block;
      height: 26px;
    }
    /* T Y P E */
    input.textarea {
      width: 100%;
      height: 50px;
      background: #fafafa;
      border: none;
      outline: none;
      padding-left: 55px;
      padding-right: 55px;
      color: #666;
      font-weight: 400;
    }

    结论 (Conclusion)

    Run the application with npm start and low and behold, your chat application is complete. At least, the basic functionality is in place. With CometChat, you could easily expand the app to include a “who’s online list”, direct messages, media messages, and a bunch of other features.

    npm start和低端运行应用程序, npm start到您的聊天应用程序已完成。 至少,基本功能已经到位。 有了CometChat,您可以轻松地扩展应用程序,使其包含“谁的在线列表”,直接消息,媒体消息以及许多其他功能。

    This article was originally published on Cometchat’s blog.

    本文最初发表在Cometchat的博客上

    翻译自: https://www.freecodecamp.org/news/building-a-modern-chat-application-with-react-js-558896622194/

    react.js做小程序

    展开全文
  • react.js做小程序 本文最初发表在Stormpath上 。 感谢您支持使SitePoint成为可能的合作伙伴。 React(有时称为React.js)是一种构建Web UI的绝妙方式。 Stormpath React SDK通过路由和组件扩展了ReactReact ...
  • smallReactApps:使用React和Redux构建的小型应用程序的集合
  • 它在生产模式下正确捆绑了React,并优化了构建以获得最佳性能。 最小化构建,文件名包含哈希。 您的应用已准备好进行部署! 有关更多信息,请参见有关的部分。 npm run deploy 为github页面构建应用程序。 在您...
  • 最小和现代的样板库,用于使用React和样式化组件构建应用程序 • 强调 比复杂 具有样式化组件 使用React挂钩 包括优化的Webpack和Babel配置 完美灯塔评分 非阻塞CSS和字体加载 友好的错误和警告 使用XO和Stylelint...
  • 一组用于构建React Native应用程序的UI组件 演示应用 开始使用 yarn add carbon-native 组件 容器 内容 H1 H2 H3 H4 H5 H6 P 一个 BR EM 强大 小号 ü 标记 徽章 import { Badge , } from ' ...
  • 我们认为这是为大多数项目构建React应用程序的正确方法。 我们已经在许多项目中使用了CRA,并且我们确信开发人员不需要关心很多例程:例如webpack config。 按照相同的原理,在基本配置之上还有其他例程,在许多...
  • 一个用于构建基于ClojureScript的React Native应用的实用程序 用法 这个很的库提供了仅需一个命令即可开始开发的功能,以及re-natal具有的一些基本功能: enable-source-maps和rebuild-index ,与renatal的enable...
  • 此仓库是一个演示如何使用React构建Conways的“人生游戏”的演示。 该应用程序使用React Context和状态Hooks。 入门 该应用程序已使用。 开始: npm install npm start 思想 《生命游戏》的业务逻辑是用纯...
  • ##wechat-react-master微信小程序开发框架,集成了Labrador,在使用该框架之前,请了解Labrador,微信小程序。本框架是为了解决了多平台开发(web,原生,微信小程序)使用一套标准架构,节约开发成本。组件化开发复用...
  • React构建的一套点菜式的抛光,可扩展和可访问表单输入。 演示和文档 安装 npm install react-widgets 当地发展与贡献 React窗口部件使用“ monorepo”组织样式来在单个git repo中管理多个npm软件包。 这是...
  • React-Trello-Multiboard是使用React构建的单页应用程序,可显示多个Trello:registered:板卡和列表的多张卡片。 卡可以由首选团队成员过滤。 目录 主要特点 :memo: 灵活的多板配置(例如,从多个板上选择要显示的...
  • React-TypeScript-101:我为了学习和练习React.js和TypeScript而构建项目和应用程序的集合
  • 它在生产模式下正确捆绑了React,并优化了构建以获得最佳性能。 生成被最小化,并且文件名包括哈希值。 您的应用已准备好进行部署! 有关更多信息,请参见关于的部分。 npm run eject 注意:这是单向操作。 ...
  • react端生成小程序码 上次 ,我开始告诉您有关如何制作游戏的故事。 我描述了如何设置异步PHP服务器,Laravel Mix构建链,React前端以及将所有这些连接在一起的WebSocket。 现在,让我告诉您有关当我开始使用React,...
  • Breathly是一个开源的React-Native移动应用程序,可让您专注于呼吸。 您可以将Breathly用于日常放松和呼吸训练:只需选择一种呼吸技术,然后专注于指导锻炼即可。 总览 在此存储库中,您将找到Breathly移动应用程序...
  • 我正在流上构建的Pokedex react应用程序 _ 特征 搜索功能 区域过滤器 名称搜寻 号码搜索 显示信息 姓名 图片 ID 按下蓝色按钮即可显示移动 随机想法 制作位于口袋妖怪图像底部的类型指示器图标 Create React App...
  • React 16是在React的新核心架构(代号为“ Fiber”)之上构建的第一个React版本。 React 16是从头开始设计的,以支持异步渲染,该异步渲染允许处理大型组件树而不会阻塞主执行线程。 它支持许多关键功能,例如使用...
  • 使用React构建的演示购物网络应用- 你可以做什么 使用电子邮件地址和密码或Google帐户注册/登录。 探索男女帽子,夹克和运动鞋。 将商品添加到购物车 从结帐页面添加/删除项目 使用Stripe的测试Visa卡付款 项目...
  • 只是一个由ReactSass构建的简单笔记应用程序 该项目是通过引导的。 可用脚本 在项目目录中,可以运行: npm start 在开发模式下运行应用程序。 打开在浏览器中查看它。 如果您进行编辑,则页面将重新加载。 您...
  • 它在生产模式下正确捆绑了React,并优化了构建以获得最佳性能。 生成被最小化,并且文件名包括哈希值。 您的应用已准备好进行部署! 有关更多信息,请参见关于的部分。 npm run eject 注意:这是单向操作。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 691
精华内容 276
关键字:

react构建小程序