誰かによってどんなウェブサイトにでも埋め込まれることができる反応「ウィジェット」をつくってください

22032 ワード

なぜ、私はこれをしますか?
つの例はあなたが作っているウィジェットの融通性のためです.クライアントか世界のどちらか.ウィジェットは、可能な限り多くの場所で、ソフトウェアの無関心に埋め込まれている必要があります.そのウェブサイトがwebflow、WordPress、Shopify、Drupalを使って作られるかどうかは、重要でありません.また、同じページに複数の時間が存在するウィジェットについても共通です.与えられたsubredditの最後の5つのポストを表示するウィジェットを想像しましょう.私は、複数のsubredditsのために同じページにそのウィジェットを複数回埋め込むことができなければなりません.
念頭に置いて、我々は反応の開発者のためのこのウィジェットを構築していません.もしそうならば、我々はちょうど反応コンポーネントを構築して、それをNPMに発行します.代わりに、誰もが使用することができますウィジェットを構築しているにもかかわらず、非コーダ、反応の外.
我々は、正確にこれをどうするかについて行きます.我々はどのように同じページにあなたの反応アプリの複数のバージョンを初期化する方法を教えることによって開始されます.次に、我々はどのようにDOMの下にデータを渡すために、私たちの反応アプリに学びます.これは、いくつかの属性を設定することによって、それぞれのウィジェットを異なる方法で提示することを可能にします.どのようにコードを知っていることなく、お客様が簡単に設定できる属性.
開始するには、作成反応アプリを使用して、典型的な反応アプリを初期化しましょう.
npx create-react-app reddit-widget
Reactdomのレンダリング関数
あなたが最初に反応アプリを作成して反応するアプリを初期化するときは、反応は単一の要素に自分自身を添付通知します.
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);
reactdomのレンダリング関数は主に2つの引数を取ります.最初は、DOMに注入される反応コンポーネントです.番目は実際のDOM要素です.
上記の場合、DOM内のCount - Ron - Rootのdivコンテナにコンポーネントをインジェクションします.あなたがパブリック/インデックスに移動して見つけることができます.HTML .
<div id="root"></div>

反応の多重インスタン
さて、我々はこの反応アプリの複数のインスタンスをしたい場合はどうなりますか?reactdomのレンダリング機能がどのように機能するかを知っています.DOM内の単一のdivに我々のアプリを注入する代わりに、複数に注入しましょう.
まず、インデックスを更新します.複数のdivを繰り返します.これを行うには、ドキュメントを使用します.QuerySelectorAllと指定されたredditCountウィジェットクラスを持つすべてのdivを検索します.その後、我々はそれらのそれぞれに我々の反応アプリを注入します.
// Find all widget divs
const WidgetDivs = document.querySelectorAll('.reddit_widget')

// Inject our React App into each
WidgetDivs.forEach(Div => {
  ReactDOM.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>,
    Div
  );
})
この時点で、我々の反応アプリは空白になります.これは、RedditCountウィジェットクラスを使用してdivを持っていないからです.私たちの公開/インデックスを更新しましょう.HTMLファイル.
   <div class="reddit_widget"></div>
    <div class="reddit_widget"></div>
偉大な、今我々は我々の反応アプリの複数のバージョンを同時に実行している!
データ属性の渡し
だから我々の反応アプリのページで複数回レンダリングしている.これ自体は役に立ちません.我々は、さまざまなデータや機能を含むように我々のアプリの各インスタンスをしたい.
ある方法のトンと反応アプリからデータを渡すためにあります.この記事では、データ属性を使用して説明します.
反応コンポーネントにおけるDOM属性の読み込み
反応では、我々のコンポーネントに有用なデータを添付する小道具を使用します.HTMLでは、データ属性があります.JavaScriptのビットと一緒に、どれだけ強力なことができます.
まず、public/indexでDOM要素にデータ属性を添付しましょう.HTML .
<div class="reddit_widget" data-subreddit="javascript"></div>
<div class="reddit_widget" data-subreddit="reactjs"></div>
さて、我々の反応アプリでこれらのデータ属性を読んでみましょう.我々がこれをすることができる多くの方法が、あります.
  • 私たちは、各DOM要素から属性を取得するために、div . getAttribute(“data subreddit”)を使用することができます.私たちは私たちの反応成分にこのredreddit支柱を渡すことができます.
  • 1 .オプション1と同様ですが、DataSetプロパティを使用します.
  • 私たちは、DOM要素全体を支柱として、我々の反応コンポーネントに渡すことができます.私たちは、各アプリケーションのDOM要素全体にアクセスすることができます.そこから、私たちはDOM要素で何かをすることができます.属性を取得するなど.
    詳細については、data attributesを使用してチェックアウトします.
  • この記事のために、我々はオプション3で行きます.
    // index.js 
    
    WidgetDivs.forEach(Div => {
      ReactDOM.render(
        <React.StrictMode>
          <App domElement={Div} />
        </React.StrictMode>,
        Div
      );
    })
    
    // src/App.js 
    
    function App({ domElement }) {
      const subreddit = domElement.getAttribute("data-subreddit")
    
      return (
        <div className="App">
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <p>
              My favorite subreddit is /r/{subreddit}
            </p>
            <a
              className="App-link"
              href="https://reactjs.org"
              target="_blank"
              rel="noopener noreferrer"
            >
              Learn React
            </a>
          </header>
        </div>
      );
    }
    
    すごい!今、我々は正常にDOMから我々の反応アプリにデータを渡しています.これは、可能性のトンにドアを開きます.我々は、DOMから渡された属性に基づいて我々のアプリの全く別のバージョンを作成することができます
    「現実世界」reddit装置の例
    この記事のために、あなたはすでにいくつかの基本的な反応概念に精通していると仮定します.IE :データの取得だけでなく、コンポーネントと小道具.それで、私はRedditのAPIからデータを引いて、リストを表示するために作られる変化に飛び込みません.あなたがこれの別々の記事を望むならば、下記にコメントしてください.しかし、私はこれがすでに広範囲に覆われていると感じます.
    このウィジェットをさらに便利にするために、“完全な”、我々はRedditのAPIからいくつかのデータを取得します.我々は、それらへのリンクとともに、最新のポストのいくらかを含めたいです.また、subreddit自体へのリンクも含めたい.最後に、ウィジェットのための一般的な実践は、“電源”通知を含めることです.特に「Freemium」価格決定モデルで.これは他の人があなたのウィジェットを発見し、また顧客になることができます.たぶん顧客を支払う.
    以下にその例を示します.
    import React, { useEffect, useState } from 'react';
    import './App.css';
    
    // Render each post
    function renderPost(post){
      const { data: { title, url, author, id } } = post
      const authorUrl = `https://www.reddit.com/u/${author}`
    
      return (
        <div className="reddit_widget__post" key={id}>
          <div className="reddit_widget__posted_by">
            posted by <a href={authorUrl} className="reddit_widget__posted_by" target="_blank" rel="noopener noreferrer">u/{author}</a>
          </div>
          <a href={url} className="reddit_widget__title" target="_blank" rel="noopener noreferrer">{title}</a>
        </div>
      )
    }
    
    // Filter, since reddit always returns stickied posts up top
    function nonStickiedOnly(post){
      return !post.data.stickied
    }
    
    function App({ domElement }) {
      const subreddit = domElement.getAttribute("data-subreddit")
      const [loading, setLoading] = useState();
      const [error, setError] = useState('');
      const [data, setData] = useState([]);
    
      useEffect(() => {
        // Fetch data from reddit
        setLoading(true)
        fetch(`https://www.reddit.com/r/${subreddit}.json`)
          .then((response) => response.json())
          .then((data) => {
            setLoading(false);
            setData(data.data.children.slice(0, 10));
          })
          .catch((e) => {
            console.log(e)
            setLoading(false);
            setError('error fetching from reddit');
          });
      }, [ subreddit ])
    
      return (
        <div className="reddit_widget__app">
          <h1 className="reddit_widget__header">
            Latest posts in <a href={`https://reddit.com/r/${subreddit}`} rel="noopener noreferrer">/r/{subreddit}</a>
          </h1>
          <div className="reddit_widget__inner">
            {loading && "Loading..."}
            {error && error}
            {!!data.length && data.filter(nonStickiedOnly).map(renderPost)}
          </div>
          <p className="reddit_widget__powered_by">
            This widget is powered by{" "}
            <a
              href="https://javascriptpros.com"
              rel="noopener noreferrer"
              target="_blank"
            >
              JavaScriptPros.com
            </a>
          </p>
        </div>
      );
    }
    
    export default App;
    
    ウィジェットのビルド
    我々は、作成反応アプリを使用して我々のアプリを初期化しました.私たちの全体の束を1つのJS&CSSファイルに取得するために、我々は小包を使用してビルドします.ビルドスクリプトを完全に置き換える代わりに、build : widgetという新しいものを追加します.この記事では、我々はあまりにも小包の作品にどのように深くダイビングはありませんが、それをチェックアウトしてください.
    まず、小包を依存関係として追加する
    yarn add --dev parcel-bundler
    
    
    アップデートパッケージ.新しいビルドスクリプトを持つJSON.これは、我々のJS(私たちのCSSを構築する)を我々のdocsディレクトリに建設するように小包に言います.ソースマップは、我々のビルドを小さく保つために必要とされません.私たちはdocsディレクトリを選びました、したがって、我々はgithubページを使用して我々の装置を公開することができます、しかし、どんなディレクトリも動きます.
    "build:widget": "parcel build src/index.js --no-source-maps -d docs",
    
    
    キャッシュディレクトリの小包を無視したい場合もあります.ジティノル
    # .gitignore
    
    # parcel 
    .cache
    
    スタイリングを含む全コードはhereである.また、ウィジェット自体hereをデモすることもできます.