1. 程式人生 > >React 腳手架介紹以及路由基本資訊

React 腳手架介紹以及路由基本資訊

create-react-app建立專案

npm install -g create-react-app
create-react-app react-cli

目錄結構介紹

圖中紅色框是我後來加的,暫時可以不考慮。


public:裡面包含了我們專案中的啟動頁面,react比較適合單頁面專案應用開發。
  • favico.ico: 這是用來表示:快捷方式 小圖示。詳情可以訪問文章
  • index.html: 初始頁面。
  • manifest.json: wepack打包優化相關,本人沒有研究過。
src:裡面包含專案檔案,最重要的是下面兩個檔案
  • index.js 專案初始執行的js。內部進行頁面元素的渲染操作。
  • App.js index.js初始載入的元件。

至於為什麼初始載入的index.html和index.js。我們可以將專案中的配置檔案顯示出來

在當前目錄下執行下面程式碼:

npm run eject //必須在當前本地沒有code change的情況下去執行,不然可能會報錯,因為我在用的時候就報錯了。

然後我們會看到目錄結構發生變化:


如圖兩個紅色框都是新加的。不過目前我最關心的是path.js。下面是部分程式碼:

module.exports = {
  dotenv: resolveApp('.env'),
  appBuild: resolveApp('build'),
  appPublic: resolveApp('public'),
  appHtml: resolveApp('public/index.html'),
  appIndexJs: resolveApp('src/index.js'),
  appPackageJson: resolveApp('package.json'),
  appSrc: resolveApp('src'),
  yarnLockFile: resolveApp('yarn.lock'),
  testsSetup: resolveApp('src/setupTests.js'),
  appNodeModules: resolveApp('node_modules'),
  publicUrl: getPublicUrl(resolveApp('package.json')),
  servedPath: getServedPath(resolveApp('package.json')),
};
如圖可以看出為什麼index.html和index.js是初始執行檔案。

路由例子

提出路由問題

單頁面應用上的hash值變化會導致頁面上渲染上不同的elements。

第一需要監控hash值的變化。

第二hash值的變化需要引起當前主元件內的state變化。(這一點相信不難理解,可以訪問前一篇文章)。

不使用React Router

//index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'))
//App.js
import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
import About from "./containers/about";
import Inbox from "./containers/inbox";
import Home from "./containers/home";

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {route: window.location.hash.substr(1)};
    }

    componentDidMount() {
        window.addEventListener('hashchange', () => { //監控hash值的變化
            this.setState({
                route: window.location.hash.substr(1) //更新state值
            })
        })
    }

    render() {
        let Child
        switch (this.state.route) { //判斷state值,渲染不同的元件
            case '/about':
                Child = About;
                break;
            case '/inbox':
                Child = Inbox;
                break;
            default:
                Child = Home;
        }

        return (
            <div>
                <h1>App</h1>
                <ul>
                    <li><a href="#/about">About</a></li>
                    <li><a href="#/inbox">Inbox</a></li>
                    <li><a href="#/home">Home</a></li>
                </ul>
                <Child/>
            </div>
        )
    }
}

export default App;
// containers/about.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class About extends Component {
    render() {
        return (
            <div>About</div>
        );
    }
}

export default About;


// containers/home.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class Home extends Component {
    render() {
        return (
            <div>Home</div>
        );
    }
}

export default Home;


// containers/inbox.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class Inbox extends Component {
    render() {
        return (
            <div>Inbox</div>
        );
    }
}

export default Inbox;


React-Route

React Router 是一個基於 React 之上的強大路由庫,它可以讓你嚮應用中快速地新增檢視和資料流,同時保持頁面與 URL 間的同步。

npm install [email protected] --save

此處說明一下:因為當前的react版本是16.3.2,因為react16的不能相容 react-router 2/3, 如果要用 react-router2/3,需將react降級到15,所以我這裡用的[email protected][email protected]

舉例:

import React from 'react';
import ReactDOM from 'react-dom'
import { Router, Route, Link } from "react-router";
import './index.css';

const App = React.createClass({
    render() {
        return (
            <div>
                <h1>App</h1>
                <ul>
                    <li><Link to="/about">About</Link></li>
                    <li><Link to="/inbox">Inbox</Link></li>
                </ul>
                {this.props.children}
            </div>
        )
    }
})

const About = React.createClass({
    render() {
        return <h3>About</h3>
    }
})

const Inbox = React.createClass({
    render() {
        return (
            <div>
                <h2>Inbox</h2>
                {this.props.children || "Welcome to your Inbox"}
            </div>
        )
    }
})

const Message = React.createClass({
    render() {
        return <h3>Message {this.props.params.id}</h3>
    }
})

ReactDOM.render((
    <Router>
        <Route path="/" component={App}>
            <Route path="about" component={About} />
            <Route path="inbox" component={Inbox}>
                <Route path="messages/:id" component={Message} />
            </Route>
        </Route>
    </Router>
), document.getElementById('root'))

路由基本配置

ReactDOM.render((
    <Router>
        <Route path="/" component={App}>
            <Route path="about" component={About} />
            <Route path="inbox" component={Inbox}>
                <Route path="messages/:id" component={Message} />
            </Route>
        </Route>
    </Router>
), document.getElementById('root'));

Router

React Router 的重要元件。它能保持UI和URL的同步,其內部包含多個路由。

children (required)

一個或多個的 Route 或 PlainRoute。當 history 改變時, <Router> 會匹配出 Route 的一個分支,並且渲染這個分支中配置的元件,渲染時保持父 route 元件巢狀子 route 元件。

routes
children 的別名。

const routes = (<Route path="/" component={App}>
    <Route path="about" component={About}/>
    <Route path="inbox" component={Inbox}>
        <Route path="messages/:id" component={Message}/>
    </Route>
</Route>);

ReactDOM.render((
    <Router children={routes} routes={routes}>

    </Router>
), document.getElementById('root'))
對於children和routes之間的區別沒有研究過,<Router children={routes} routes={routes}>二者任意一個存在,路由都可以執行。還有其他的props,這種就需要自己拓展了。

Route

Route 是用於宣告路由對映到應用程式的元件層。
<Route path="/" component={App}>
    <Route path="about" component={About} />
    <Route path="inbox" component={Inbox}>
        <Route path="messages/:id" component={Message} />
    </Route>
</Route>
path
URL 中的路徑。它會以父元件路由為基礎,除非它是從/開始的, 將它變成一個絕對路徑。
父子元件如何判斷,可以看出<Route></Route>內部的Route元件都是可能出現的子元件。
<Route path="/App" component={App}>
    <Route path="about" component={About} />
    <Route path="/inbox" component={Inbox}>
        <Route path="messages/:id" component={Message} />
    </Route>
</Route>

這個例子中中,/App/about可以訪問到About元件,但是/App/inbox訪問不到InBox元件。因為路由path以/開頭。

component
當匹配到URL時,單個的元件會被渲染。它可以被父route 元件的this.props.children渲染。這個知識點很重要,因為父子元件通過路由渲染的過程中,是需要一個地方渲染對應元件內容。所以每個父元件都會設定this.props.children來劃定一個渲染子元件的區域。

const App = React.createClass({
    render() {
        return (
            <div>
                <h1>App</h1>
                <ul>
                    <li><Link to="/about">About</Link></li>
                    <li><Link to="/inbox">Inbox</Link></li>
                </ul>
                {this.props.children}
            </div>
        )
    }
})
components
Route 可以定義一個或多個已命名的元件,當路徑匹配到 URL 時,它們作為 name:component 對的一個物件去渲染。它們可以被父route元件的this.props[name] 渲染。
這裡的含義是:子路由的變化會導致父元件的多處變化。下面例子是父元件中有兩塊不相接的區域會隨著路由的變化而變化。這裡其實將子元件按照路由的變化然後傳入到父元件的props中。

import React from 'react';
import ReactDOM from 'react-dom'
import {Router, Route, Link} from "react-router";
import './index.css';

const App = React.createClass({
    render() {
        const { main, sidebar } = this.props
        return (
            <div>
                <h1>App</h1>
                <div className="Main">
                    {main}
                </div>
                <ul>
                    <li><Link to="/groups">groups</Link></li>
                    <li><Link to="/users">users</Link></li>
                </ul>
                <div>
                    <div className="Sidebar">
                        {sidebar}
                    </div>
                </div>
            </div>
        )
    }
})

const Groups = React.createClass({
    render() {
        return <h3>Groups</h3>
    }
})

const GroupsSidebar = React.createClass({
    render() {
        return (
            <div>
                <h2>GroupsSidebar</h2>
            </div>
        )
    }
})

const Users = React.createClass({
    render() {
        return <h3>Users</h3>
    }
})

const UsersSidebar = React.createClass({
    render() {
        return (
            <div>
                <h2>UsersSidebar</h2>
                <h3>{this.props.children}</h3>
            </div>
        )
    }
})

const Profile = React.createClass({
    render() {
        return (
            <div>
                <h2>Profile {this.props.params.id}</h2>
            </div>
        )
    }
})

const routes = (
    <Route path='/' component={App}>
        <Route path="groups" components={{main: Groups, sidebar: GroupsSidebar}}/>
        <Route path="users" components={{main: Users, sidebar: UsersSidebar}}>
            <Route path="users/:userId" component={Profile}/>
        </Route>
    </Route>
)

ReactDOM.render((
    <Router children={routes}>
    </Router>
), document.getElementById('root'))

Link

允許使用者瀏覽應用的主要方式。<Link> 以適當的 href 去渲染一個可訪問的錨標籤。
<Link> 可以知道哪個 route 的連結是啟用狀態的,並可以自動為該連結新增 activeClassName 或 activeStyle。
to
跳轉連結的路徑,如 /users/123。
query
已經轉化成字串的鍵值對的物件。
hash
URL 的 hash 值,如 #a-hash。
注意:React Router 目前還不能管理滾動條的位置,並且不會自動滾動到 hash 對應的元素上。如果需要管理滾動條位置,可以使用 scroll-behavior 這個庫。
state
儲存在 location 中的 state。
activeClassName
當某個 route 是啟用狀態時,<Link> 可以接收傳入的 className。失活狀態下是預設的 class。
activeStyle
當某個 route 是啟用狀態時,可以將樣式新增到連結元素上。

新增首頁

首頁就是父元件初始渲染的頁面,也可以說是父元件的預設渲染頁面,使用 IndexRoute 來設定一個預設頁面。IndexRoute對應的元件將會渲染到App中的this.props.children處。
<Route path="/" component={App}>
    <IndexRoute component={Dashboard} />
    <Route path="about" component={About}/>
    <Route path="inbox" component={Inbox}>
        <Route path="messages/:id" component={Message}/>
    </Route>
</Route>

頁面跳轉

當我們修改了url之後,如下訪問messages/1的路由從/inbox/messages/:id -> /messages/:id,這個時候為了相容舊的url,則需要使用Redirect:
<Route path="/" component={App}>
    <IndexRoute component={Dashboard} />
    <Route path="about" component={About}/>
    <Route path="inbox" component={Inbox}>
        <Route path="/messages/:id" component={Message}/>
        <Redirect from="messages/:id" to="/messages/:id" />
    </Route>
</Route>

進入和離開的Hook

Route 可以定義 onEnter 和 onLeave 兩個 hook ,這些hook會在頁面跳轉確認時觸發一次。這些 hook 對於一些情況非常的有用,例如許可權驗證或者在路由跳轉前將一些資料持久化儲存起來。但是下面例子中我的測試,二者不不能共存,如果二者同時存在,onLeave沒有作用。
import React from 'react';
import ReactDOM from 'react-dom'
import {Router, Route, Link} from "react-router";
import './index.css';
import IndexRoute from "react-router/es6/IndexRoute";
import Redirect from "react-router/es6/Redirect";

const App = React.createClass({
    render() {
        return (
            <div>
                <h1>App</h1>
                <ul>
                    <li><Link to="/about">About</Link></li>
                    <li><Link to="/inbox">Inbox</Link></li>
                </ul>
                {this.props.children}
            </div>
        )
    }
})

const About = React.createClass({
    render() {
        return <h3>About</h3>
    }
})

const Inbox = React.createClass({
    render() {
        return (
            <div>
                <h2>Inbox</h2>
                {this.props.children || "Welcome to your Inbox"}
            </div>
        )
    }
})

const Message = React.createClass({
    render() {
        return <h3>Message {this.props.params.id}</h3>
    }
})

const Dashboard = React.createClass({
    render() {
        return <h3>Hello!</h3>
    }
})

 const EnterHook = function(RouterState, RedirectFunction, callback) {
    console.log("進入about");
}

const LeaveHook = function(RouterState) {
    console.log("離開about");
}

const routes = (
    <Route path="/" component={App}>
        <IndexRoute component={Dashboard} />
        <Route path="about" onLeave={LeaveHook} onEnter={EnterHook}  component={About}/>
        <Route path="inbox" component={Inbox}>
            <Route path="/messages/:id" component={Message}/>
            <Redirect from="messages/:id" to="/messages/:id" />
        </Route>
    </Route>);

ReactDOM.render((
    <Router children={routes}>
    </Router>
), document.getElementById('root'))

替換的配置方式

因為 route 一般被巢狀使用,所以使用 JSX 這種天然具有簡潔巢狀型語法的結構來描述它們的關係非常方便。然而,如果你不想使用 JSX,也可以直接使用原生 route 陣列物件。
const routes = [
    { path: '/',
        component: App,
        indexRoute: { component: Dashboard },
        childRoutes: [
            { path: 'about', component: About },
            { path: 'inbox',
                component: Inbox,
                childRoutes: [
                    { path: '/messages/:id', component: Message }
                ]
            }
        ]
    }
]

路由匹配

<Route path="/hello/:name">         // matches /hello/michael and /hello/ryan
<Route path="/hello(/:name)">       // matches /hello, /hello/michael, and /hello/ryan
<Route path="/files/*.*">           // matches /files/hello.jpg and /files/hello.html
<Route path="/**/*.jpg">            // matches /files/hello.jpg and /files/path/to/file.jpg

Index Links

IndexLink的意義在於只有當前的路由匹配的情況下才會顯示啟用狀態,下面舉個例子:路由匹配到/inbox,此時下面第一個和第三個link都顯示已啟用。但是第二個不會,因為當前的路由是/inbox,不是/。只有當路由為/,第二個link才會啟用。
<ul>
    <li><Link activeClassName='active' to="/">About</Link></li>
    <li><IndexLink activeClassName='active' to="/">About</IndexLink></li>
    <li><Link activeClassName='active' to="/inbox">Inbox</Link></li>
</ul>

browserHistory

React Router 是建立在 history 之上的。 簡而言之,一個 history 知道如何去監聽瀏覽器位址列的變化, 並解析這個 URL 轉化為 location 物件, 然後 router 使用它匹配到路由,最後正確地渲染對應的元件。

常用的 history 有三種形式, 但是你也可以使用 React Router 實現自定義的 history。

browserHistory
hashHistory

createMemoryHistory

在我沒有使用任何的方式的情況下,路由形如下面:

http://localhost:3000/inbox#/?_k=iawvme

然後修改程式碼如下,加上history={browserHistory}

<Router history={browserHistory} children={routeConfig}>

路由變化就是:http://localhost:3000/inbox

動態路由

React Router 裡的路徑匹配以及元件載入都是非同步完成的,不僅允許你延遲載入元件,並且可以延遲載入路由配置。在首次載入包中你只需要有一個路徑定義,路由會自動解析剩下的路徑。
Route 可以定義 getChildRoutes,getIndexRoute 和 getComponents 這幾個函式。它們都是非同步執行,並且只有在需要時才被呼叫。我們將這種方式稱之為 “逐漸匹配”。 React Router 會逐漸的匹配 URL 並只加載該 URL 對應頁面所需的路徑配置和元件。
const CourseRoute = {
  path: 'course/:courseId',

  getChildRoutes(location, callback) {
    require.ensure([], function (require) {
      callback(null, [
        require('./routes/Announcements'),
        require('./routes/Assignments'),
        require('./routes/Grades'),
      ])
    })
  },

  getIndexRoute(location, callback) {
    require.ensure([], function (require) {
      callback(null, require('./components/Index'))
    })
  },

  getComponents(location, callback) {
    require.ensure([], function (require) {
      callback(null, require('./components/Course'))
    })
  }
}

這裡的思想很簡單,我們來類比一下:

const routeConfig = [
    { path: '/',
        component: App,
        indexRoute: { component: Dashboard },
        childRoutes: [
            { path: 'about', component: About },
            { path: 'inbox',
                component: Inbox,
                childRoutes: [
                    { path: '/messages/:id', component: Message }
                ]
            }
        ]
    }
]
我們以/為例:getChildRoutes方法回去訪問子路由的檔案,首先說明這裡的子路由檔案是一個路由,不是一個簡單的元件。子路由檔案的格式和上面的類似,也可能會有這幾個方法。另外兩個方法訪問的就是具體的元件了。

跳轉前確認

React Router 提供一個 routerWillLeave 生命週期鉤子,這使得 React 元件可以攔截正在發生的跳轉,或在離開 route 前提示使用者。routerWillLeave 返回值有以下兩種:

return false 取消此次跳轉

return 返回提示資訊,在離開 route 前提示使用者進行確認。

需要先引入mixins: [ Lifecycle ]

const About = React.createClass({
    mixins: [ Lifecycle ],

    routerWillLeave(nextLocation) {
        return 'Your work is not saved! Are you sure you want to leave?'
    },

    render() {
        return <h3>About</h3>
    }
})

獲取路由引數

元件的生命週期內我們可以通過this.props.params獲取到。


寫在最後:react 路由知識還有許多東西需要探索,但是可以先了解基本知識再去拓展,對於版本的升級可以上網簡單搜尋一下,應該就可以解決了。最後吐槽一下react的生態圈真的不如angular。

相關推薦

React 腳手架介紹以及路由基本資訊

create-react-app建立專案npm install -g create-react-app create-react-app react-cli目錄結構介紹圖中紅色框是我後來加的,暫時可以不考慮。public:裡面包含了我們專案中的啟動頁面,react比較適合單頁

數理統計基本介紹以及介紹總體、樣本和方差

img 分享圖片 In 分享 alt info 介紹 技術分享 樣本 數理統計基本介紹以及介紹總體、樣本和方差

Spring 事務——事務介紹以及事務在Spring框架中的基本實現

事務介紹 事務一般發生在和持久層打交道的地方,比如資料庫。 假設一個工作由兩件事共同組成,那麼這兩件事要麼全部完成,這個工作才算完成。要麼全部回退到初始狀態。不存在只完成一件,還有一件事沒完成的。這項工作可稱為一個事務。常用的場景就是銀行轉賬。A向B轉賬100元這項工作由兩件事組成:A帳

Git介紹以及基本操作

介紹 Git優勢 大部分操作在本地完成不需要連網; Git是分散式的管理工具,本地就有一個倉庫並儲存了完整的版本歷史,大部分操作在本地就可以完成,這是傳統的集中式管理工具無法做的; 完整性儲存 Git會對每一次儲存的資料進行Hash演算法並將Hash值儲存

大陸居民身份證、港澳臺居民居住證驗證工具 Python 版 :驗證、獲取基本資訊以及生成假資料

中華人民共和國居民身份證、中華人民共和國港澳居民居住證以及中華人民共和國臺灣居民居住證號碼驗證工具(Python 版)支援 15 位與 18 位號碼。 PHP 版本 安裝 pip install id-validator 使用 440308199901101512 和 610104620927690

monkey介紹以及基本命令

一、Monkey 簡介 Monkey 就是SDK中附帶的一個工具。Monkey是Android中的一個命令列工具,可以執行在模擬器裡或實際裝置中。它向系統傳送偽隨機的使用者事件流(如按鍵輸入、觸控式螢幕輸入、手勢輸入等),實現對正在開發的應用程式進行壓力測試。Monkey測試是一種為了測試軟體的穩定性、健壯性

SpringMVC 整合velocity以及介紹velocity的基本使用語法

Velocity模板(VM)語言介紹以及與MVC整合 Velocity是一個基於java的模板引擎(template engine)。它允許任何人僅僅簡單的使用模板語言(template language)來引用由java程式碼定義的物件。 當Velocity應用於web開

AutoMapper介紹以及基本使用。

博主宣告:本文章為翻譯文章,原文地址(點我進入) 翻譯時間:20181220 AutoMapper介紹以及基本使用。 AutoMapper8.0: 什麼是AutoMapper? AutoMapper是一個簡單的小型庫,用於解決一個看似複雜的問題 - 擺脫將一個物件對映到另一

MySql學習筆記-介紹以及基本操作

Mysql資料型別 1: Text 型別: CHAR(size) 儲存固定長度的字串(可包含字母、數字以及特殊字元)。在括號中指定字串的長度。最多 255 個字元。 VARCHAR(size) 儲存可變長度的字串(可包含字母、數字以及特殊字元)。在括號中指定字串的最大長度。

JPA基本介紹以及使用

JPA即Java Persistence Architecture,Java持久化規範,從EJB2.x版本中原來的實體Bean分離出來的,EJB3.x中不再有實體Bean,而是將實體Bean放到JPA中來實現。可以說,JPA借鑑了Hibernate的設計,JPA的設計者就是Hibernate框架的作者。

PHP JpGraph類庫的介紹以及基本用法

JpGraph是一個面向物件的圖形建立庫,用於PHP5(> = 5.1)和PHP7.0該庫完全用PHP編寫,可以在任何PHP指令碼中使用(支援CGI / APXS / CLI版本的PHP),現在最新的版本是4.2.6( JpGraph 4.x系列支援PHP5(PHP 5.1.0或更

面試題7:介紹JS的基本資料型別以及JS的內建物件

基本資料型別:Undefined  Null  Boolean  Number  String內建物件:Object是Javascript中所有物件的父物件               資料封裝物件:Object  Array  Boolean   Number  Strin

微信公眾號獲取OpenId(使用者授權)(無需關注公眾號)以及獲取使用者基本資訊

上一個部落格也寫了微信公眾號獲取OpenId,但是現在這個和上一個有什麼區別呢。 其實呢,是差不多的,只是這個是通過使用者授權。 但是,又會有人問了,明明可以未授權獲取到使用者的openId,那我為什麼要讓使用者進行授權呢,我偷偷的獲取不就好了嗎? 好像很有道理,但是呢,

Java ExecutorService四種執行緒池基本介紹以及相關舉例

1、new Thread的弊端 執行一個非同步任務你還只是如下new Thread嗎? new Thread(new Runnable() { @Override public void run() { // TODO Auto-gene

重新認識React以及重新搭建React腳手架(0)

第一次開始學習React是今年的5月份,之前一直是直接寫JS和CSS,也沒有打包,直接載入,沒什麼複雜的東西。後來開始使用React,使用以後就有點愛不釋手 之前實現起來比較複雜的東西,現在也可以簡單的實現 只不過動畫是個弱項,不過我依賴了JQ庫,這樣就可以直接使用一些網站

Android 聯絡人資料庫介紹以及對聯絡人的基本操作

一、 聯絡人資料庫 聯絡人的資料庫檔案的位置 /data/data/com.Android.providers.contacts/databases.contacts2.db 資料庫中重要的幾張表 1、contacts表 該表儲存了所有的手

react-redux高階元件connect方法使用介紹以及實現原理

redux 講connect之前先來回顧一下redux的基本用法, 見下面的例子: import { createStore } from 'redux'; function counter(state = 0, action) { switch

2+6多機安裝部署、部分異常處理以及使用configtxlator對區塊基本資訊查詢(kafka共識,手動非docker方式)

根據蒐集的資料安裝測試並在安裝測試過程中整理的文件,如有不足希望不吝賜教。 本文介紹CentOS7中hyperledger-fabric1.1多機部署使用kafka共識非docker方式,大體上與之前solo共識的步驟類似,(solo共識:《CentOS7中hyperle

Android四大基本元件介紹以及四大元件的生命週期

這次認真閱讀了別人寫的Android四大基本元件的介紹以及四大元件的生命週期。別人寫得真的是很好。所以把連結記錄下來,以後可以再次的複習。http://www.cnblogs.com/bravestarrhu/archive/2012/05/02/2479461.html;

Hive的基本介紹以及常用函式

一、Hive的簡介:   Hive是基於Hadoop的一個數據倉庫工具,可以將結構化的資料檔案對映為一張表,並提供類SQL查詢功能。 優點: 1) 操作介面採用類SQL語法,提供快速開發的能力(簡單、容易上手)。 2) 避免了去寫MapReduce,減少開發人員的學習成本。 3) Hive的執行延遲比較