React与Google Apps脚本

15

有人尝试过将 React 前端部署到 Google Apps Script 网络应用程序吗?我正在尝试构建一个单页面前端,调用一些 Google Apps Script API,例如获取驱动器文件列表并将一些结果保存到电子表格中。然而,所有的 React 文档似乎都默认我在使用 Node.js 后端,并没有太多关注自定义构建/部署方案。如果您曾经看到过使用 Google Apps Script 的 React 的简单示例,那将不胜感激!谢谢。


请查看npm上的gas-react。它非常易于使用,可以处理您的所有服务器捆绑等。 - Jazz
4个回答

13

我在React方面没有任何经验,但是他们文档中的“Hello, World”起始示例在HTML模板中按预期工作。以下脚本与电子表格绑定,但同样适用于Web应用程序。

请注意<script>标记的属性type="text/babel"是必需的。

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
     <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

  </head>
  <body id="root">

  <script type="text/babel">

   ReactDOM.render(<h1>Hello, world!</h1>, document.getElementById('root'));

  </script>
  </body>
</html> 

在谷歌表侧边栏中的结果:

输入图像描述


1
这得益于iFrame Sandbox Mode,过去并不是很简单。感谢提供的示例。 - contributorpw
嘿@oshliaer,你能解释一下为什么iFrame沙盒模式会使这更简单吗? - dobby
@ASKER 所有沙盒模式现在都已经停用,除了IFRAME。现在它并不重要。 - contributorpw

9
在这里有许多非常棒的项目,包括一个全功能演示应用程序,展示如何在Google Apps Script中使用React:

https://github.com/enuchi/React-Google-Apps-Script

它使用clasp和webpack,因此您可以为.gs服务器端代码使用所有新的JavaScript功能(例如箭头函数,const/let等)。


我对此有一个问题,就是没有支持任何状态管理系统,比如MobX...如果有一个可以与这个项目一起使用的MobX版本,我会立刻加入! - Mike Warren

4

https://github.com/marth141/react-gas

虽然这个问题被问了很久,但我刚刚写了一个关于Google Apps Script的React事情。

您可以将其用作样板文件。使用src文件夹中的clasp将代码推送和拉回到Google Apps Script。


1
当我向下滚动时,看到了你的帖子... 你的样板很棒!我希望我的回答不会减少你的辛勤工作。如果你认为它会的话,我可以把它删掉,没问题的。 - Jason Allshorn
完全不是这样!这很酷,伙计 :) 代码越多,越好! - Sero
能否在 Google Sheets 中使用 Redux DevTools? - pauljeba
@pauljeba我老实说,我不知道。我看到过一些在Google应用脚本中使用JavaScript的更疯狂的用户。这个解决方案相当古老,使用的是V8引擎之前和今天的TypeScript。然而,仍然似乎常规的使事情工作的方法是使用CDN... 我认为你可能可以,并且可能有更好的方法出现了:)! - Sero

3

我完全被安东的惊人想法所启发!太棒了!为了补充他的想法,这里有一个类似模块的应用脚本和一个基础的App类,我已经将redux混合进来。

Code.gs

function include(filename) {
Logger.log(filename)
  return HtmlService.createHtmlOutputFromFile(filename).getContent();
}

function onOpen() {
  SlidesApp.getUi().createMenu('Picker')
      .addItem('Start', 'showSidebar')
      .addToUi();
}

function showSidebar() {
        var ui = HtmlService.createTemplateFromFile('Index').evaluate().setTitle(
            'Flashcards');
        SlidesApp.getUi().showSidebar(ui);
}

App.js.html

<script type="text/babel">
class App extends React.Component {
  constructor(){
    super();
  }
  render() {
    return (
    <div>Hello World</div>
    )
  }
}

</script>

index.js.html - 不使用redux

  <script type="text/babel">
   ReactDOM.render(<App />, document.getElementById('root'));
  </script>

使用Redux的index.js.html文件

<script type="text/babel">  
   const Provider = ReactRedux.Provider
   ReactDOM.render(
     <Provider store={store}>
       <App />
     </Provider>, 
     document.getElementById('root'));
</script>

Index.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    // Libraries for adding redux
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.7/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.0/redux.min.js"></script>

<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

  </head>
  <body>
  <div id="root"></div>
  <?!= include('App.js'); ?>
  // pull in redux if and when needed
  <?!= include('redux.js'); ?>
  <?!= include('index.js'); ?>
  </body>
</html> 

redux.js.html

<script type="text/babel">      
  const initialState = {
    result: 1, 
    lastValues: []
  }


  const reducer = (state = initialState, action) => {
    switch (action.type){
      case "ADD": 
          state = {
            ...state,
            result : state.result + action.payload,
            lastValues: [...state.lastValues, action.payload]
          }          
        break;
    }
    return state;
  };  
  const store = Redux.createStore(reducer);

  store.subscribe( () => {
    console.log('Store updated!', store.getState());
  })

  store.dispatch({ type: "ADD", payload: 10 })
</script>

顺便问一下,在GAS插件中使用单页应用程序框架不被禁止吗? - dobby
您能否在Google Sheets中从Redux DevTools中看到状态更改? - pauljeba

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接