Elasticsearch > Reactivesearch에서 좋은 느낌의 검색 SPA를 만들려고했습니다.

Reactivesearch v3에서 좋은 느낌의 검색 SPA를 30분 정도로 만들기 - Qiita

참고로 자신의 환경에서 해본 메모입니다.

install react app


npx create-react-app steam-search
cd steam-search
@appbaseio/reactivesearch 를 넣습니다.
yarn add @appbaseio/reactivesearch

시작
yarn start

부팅이 확인되면 src/App.js를 변경합니다.

src/App.js
import React, {Component} from 'react';
import {DataSearch, ReactiveBase, ReactiveList, ResultList, SelectedFilters} from '@appbaseio/reactivesearch';
import './App.css';

const { ResultListWrapper } = ReactiveList;

class App extends Component {
    render() {
        return (
            <div className="main-container">
                <ReactiveBase
                    app="steam-search"
                    url="http://localhost:9200"
                    credentials="elastic:changeme"
                >
                    <DataSearch
                        componentId="title"
                        dataField={["ResponseName"]}
                        queryFormat="and"
                    />
                    <SelectedFilters/>
                    <ReactiveList
                        componentId="resultLists"
                        dataField="ResponseName"
                        size={10}
                        pagination={true}
                        react={{
                            "and": ["title"]
                        }}
                    >
                        {({data}) => (
                            <ResultListWrapper>
                                {
                                    data.map(item => (
                                        <ResultList key={item._id}>
                                            <ResultList.Content>
                                                <ResultList.Title
                                                    dangerouslySetInnerHTML={{
                                                        __html: item.ResponseName
                                                    }}
                                                />
                                            </ResultList.Content>
                                        </ResultList>
                                    ))
                                }
                            </ResultListWrapper>
                        )}
                    </ReactiveList>
                </ReactiveBase>
            </div>
        );
    }
}

export default App;
  • app를 Elasticsearch에서 만든 색인 이름으로 변경합니다.
    app="steam-search"
  • 인증을 설정하지 않은 경우, credentials="elastic:changeme" 의 행마다 삭제합니다.

  • 아래 화면으로 바뀌면 OK. 변하지 않는 경우에는 하단의 CORS를 참조해 주세요


    CORS



    화면이 흰색이면 CORS 설정이 제대로 수행되지 않을 수 있습니다.


    from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
    

    이 경우 elasticsearch 구성 파일 elasticsearch.yml에 추가합니다.

    elasticsearch.yml
    http.cors.enabled: true
    http.cors.allow-origin: "*"
    

    최종형



    자세한 내용은 Reactivesearch v3에서 좋은 느낌의 검색 SPA를 30분 정도로 만들기 - Qiita
    를 보시면 다음과 같이 변경합니다.

    app.js


    import React, {Component} from 'react';
    import {DataSearch, ReactiveBase, ReactiveList, ResultList, SelectedFilters} from '@appbaseio/reactivesearch';
    import './App.css';
    import './SteamSearch.css'
    
    const {ResultListWrapper} = ReactiveList;
    
    class App extends Component {
        render() {
            return (
                <div className="main-container">
                    <ReactiveBase
                        app="steam-search" ← ElasticsearchのIndex名にする
                        url="http://localhost:9200"
                        credentials="elastic:changeme" ←  認証がなければ削除する
                        theme={
                            {
                                typography: {
                                    fontFamily: 'Arial, Helvetica, sans-serif',
                                    fontSize: '16px',
                                },
                                colors: {
                                    titleColor: '#c7d5e0',
                                    textColor: '#c7d5e0',
                                    backgroundColor: '#212121',
                                    primaryColor: '#2B475E',
                                }
                            }
                        }
                    >
                        <DataSearch
                            componentId="title"
                            dataField={["ResponseName"]}
                            queryFormat="and"
                            placeholder="enter search term"
                            showIcon={false}
                            title="Steam Search"
                            className="data-search"
                            innerClass={{
                                input: 'input',
                                list: 'list',
                            }}
                        />
                        <SelectedFilters/>
                        <ReactiveList
                            componentId="resultLists"
                            dataField="ResponseName"
                            size={25}
                            pagination={true}
                            react={{
                                "and": ["title"]
                            }}
                            sortOptions={[
                                {label: "Best Match", dataField: "_score", sortBy: "desc"},
                                {label: "Lowest Price", dataField: "PriceInitial", sortBy: "asc"},
                                {label: "Highest Price", dataField: "PriceInitial", sortBy: "desc"},
                            ]}
                            className="result-list"
                            innerClass={{
                                resultsInfo: "resultsInfo",
                                resultStats: "resultStats",
                            }}
                        >
                            {({data}) => (
                                <ResultListWrapper>
                                    {
                                        data.map(item => (
                                            <ResultList
                                                key={item._id}
                                                href={`https://store.steampowered.com/app/${item.ResponseID}`}
                                                className="listItem"
                                            >
                                                <ResultList.Image className="image" src={item.HeaderImage}/>
                                                <ResultList.Content>
                                                    <ResultList.Title
                                                        dangerouslySetInnerHTML={{
                                                            __html: item.ResponseName
                                                        }}
                                                    />
                                                    <ResultList.Description>
                                                        <p className="releaseDate">{item.ReleaseDate}</p>
                                                        <p className="price">${item.PriceInitial}</p>
                                                    </ResultList.Description>
                                                </ResultList.Content>
                                            </ResultList>
                                        ))
                                    }
                                </ResultListWrapper>
                            )}
                        </ReactiveList>
                    </ReactiveBase>
                </div>
            );
        }
    }
    
    export default App;
    

    css



    SteamSearch.css

    SteamSearch.css
    @font-face {
        font-family: "IonIcons";
        src: url("//code.ionicframework.com/ionicons/2.0.1/fonts/ionicons.eot?v=2.0.1");
        src: url("//code.ionicframework.com/ionicons/2.0.1/fonts/ionicons.eot?v=2.0.1#iefix") format("embedded-opentype"), url("//code.ionicframework.com/ionicons/2.0.1/fonts/ionicons.ttf?v=2.0.1") format("truetype"), url("//code.ionicframework.com/ionicons/2.0.1/fonts/ionicons.woff?v=2.0.1") format("woff"), url("//code.ionicframework.com/ionicons/2.0.1/fonts/ionicons.svg?v=2.0.1#Ionicons") format("svg");
        font-weight: normal;
        font-style: normal
    }
    
    html {
        min-height: 100%;
    }
    
    body {
        background-color: #1B3C53;
        background-image: linear-gradient(315deg, #000000 0%, #1B3C53 74%);
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
    }
    
    .main-container {
        width: 616px;
        margin-top: 20px;
    }
    
    .data-search .input {
        color: white;
    }
    
    .data-search .list li {
        background-color: #aaa !important;
        color: #000;
        overflow: hidden;
    }
    
    .data-search .list li:target {
        background-color: #666 !important;
    }
    
    .resultsInfo {
        position: relative;
    }
    
    .resultsInfo:before {
        z-index: 1;
        position: absolute;
        right: 15px;
        top: 0;
        content: "\f123";
        font-family: "IonIcons";
        line-height: 43px;
        color: #7F878C;
        pointer-events: none;
    }
    
    .resultsInfo select {
        background-color: #18394D;
        color: #67c1f5;
        outline: 1px solid #000;
        background: transparent;
        background-image: none;
        padding-right: 50px;
    }
    
    .resultsInfo option {
        background-color: #417A9B;
        color: #fff;
    }
    
    .result-list .resultStats {
        color: #3b6e8c;
    }
    
    .result-list .listItem {
        background-color: #16202D;
        padding: 0;
        margin: 2px 0;
        border: 0;
        background: rgba(0, 0, 0, 0.4);
    }
    
    .result-list .listItem:hover {
        background: rgba(0, 0, 0, 0.8);
    }
    
    .result-list .image {
        width: 120px;
        height: 45px;
    }
    
    .result-list article, .result-list article div {
        display: flex;
        align-items: center;
    }
    
    .result-list article h2 {
        padding: 0;
    }
    
    .releaseDate {
        color: #4c6c8c;
        width: 150px;
    }
    
    .price {
        width: 50px;
    }
    
    input {
        background-color: #1C3345 !important;
        border: 1px solid #000 !important;
    }
    

    좋은 웹페이지 즐겨찾기