반응형

 Rx JS를 통해 github로 user정보를 요청하고 응답받는 예제입니다.

 

https://api.github.com/search/users?q="검색할git ID" 

해당 URL을 통해 JSON형태의 메시지를 전달받고 메시지를 출력하는 예제를 진행해보겠습니다.

 

 

 

Github유저의 ID를 검색하고 파싱하기

rx.js

import { fromEvent, Observable } from 'rxjs';
import {
    map,
    debounceTime,
    filter,
    distinctUntilChanged,
    partition,
    tap,
    switchMap,
    retry,
    finalize,
    share
} from 'rxjs/operators';
import { ajax } from 'rxjs/ajax';

let $layer, $loading;
window.onload = function() {
    $layer = document.getElementById('suggestLayer');
    $loading = document.getElementById('loading');
};

function drawLayer(target, items) {
    target.innerHTML = items
        .map(user => {
            return `<li class="user">
                        <img src="${user.avatar_url}" width="50px" height="50px" />
                        <p><a href="${user.html_url}" target="_blank">${user.login}</a></p>
                    </li>`;
        })
        .join('');
}

function showLoading() {
    return new Observable(observer => {
        const subscription = observable.subscribe({
            next() {
                $loading.style.display = 'block';
            },
            complete() {}
        });
    });
}
function hideLoading() {
    return new Observable(observer => {
        const subscription = observable.subscribe({
            next() {
                $loading.style.display = 'none';
            },
            complete() {}
        });
    });
}

const keyup$ = fromEvent(document, 'keyup').pipe(
    debounceTime(300),
    filter(f => f.target.id === 'searchId'),
    map(e => e.target.value),
    distinctUntilChanged(),
    tap(v => console.log('from keyup$', v)),
    share()
);

let [user$, reset$] = keyup$.pipe(partition(query => query.trim().length > 0));

user$ = user$.pipe(
    tap(showLoading),
    switchMap(query =>
        ajax.getJSON(`https://api.github.com/search/users?q=${query}`)
    ),
    tap(hideLoading),
    retry(2),
    finalize(hideLoading)
);
user$.subscribe({
    next: v => drawLayer($layer, v.items),
    error: e => {
        console.log(e);
    }
});
reset$
    .pipe(
        tap(v => ($layer.innerHTML = '')),
        tap(v => console.log('from reset$', v))
    )
    .subscribe();

 

 

 

index.html

<html>
    <link rel="stylesheet" href="./src/style.css" />
    <script src="main_bundle.js"></script>
    <h1>RxJS GitHub User Map</h1>

    <p>Please enter the name of the user you want to search for...</p>
    <div class="autocomplete">
        <input
            type="text"
            id="searchId"
            placeholder="Please enter your ID..."
        />
        <ul id="suggestLayer"></ul>

        <div id="loading">
            <i class="fas fa-spinner fa-pulse"></i>
        </div>
    </div>
</html>

 

 

style.css

ul {
    list-style-type: none !important;
}
li {
    display: block;
}
.autocomplete {
    position: relative;
    width: 300px;
}
#searchId {
    width: 100%;
    height: 50px;
    line-height: 50px;
    font-size: 20px;
}
#suggestLayer {
    position: absolute;
    color: #666;
    padding: 0;
    margin: 0;
    width: 100%;
}
#suggestLayer li {
    border: 1px solid #bec8d8;
}
.user img {
    position: relative;
    float: left;
    margin-right: 10px;
}
.user p {
    line-height: 50px;
    margin: 0;
    padding: 0;
}
#loading {
    position: absolute;
    z-index: 2;
    top: 2px;
    right: 0;
    display: none;
}

 

 

package.json

{
    "name": "rxjsproj",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "publish": "webpack && webpack-dev-server --output-public=/dev/",
        "watch": "webpack --watch",
        "build": "webpack",
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "@fortawesome/fontawesome-free": "^5.4.0",
        "@babel/core": "^7.8.7",
        "@babel/preset-env": "^7.8.7",
        "babel-loader": "^8.0.6",
        "esm": "^3.2.25",
        "rxjs": "^6.5.4",
        "webpack": "^4.42.0",
        "webpack-cli": "^3.3.11",
        "webpack-dev-server": "^3.10.3"
    },
    "dependencies": {
        "react-hot-loader": "^4.12.20"
    }
}

 

 

 

webpack.config.js

var path = require('path');

module.exports = {
    entry: {
        app: './src/rx.js'
    },
    output: {
        path: path.resolve(__dirname, 'dev'),
        filename: 'main_bundle.js'
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /\.(js)$/,
                include: path.resolve(__dirname, 'src'),
                loader: 'babel-loader',
                query: {
                    presets: ['@babel/preset-env']
                }
            }
        ]
    }
};

 

 

결과

동작 gif

 

 

참고사이트 : https://uxicode.tistory.com/m/402?category=456750

 

RxJs study - 자동완성 UI

 

uxicode.tistory.com

 

반응형