Я работаю над reactjs проектом, довольно новым для этой технологии. У меня есть ответ API-данных, в котором проводится различие между продуктами, т. Е. Внутренними продуктами (которые загружаются из приложения) и внешними продуктами (которые сканируются с других веб-сайтов). Для большей ясности ответ API json выглядит следующим образом.
[
{
"id": 0,
"title": "TestProductForAzure",
"description": null,
"owner": "Seeded Company",
"url": "http://localhost:54729/api/product/3",
"type": "Internal",
"rank": 0,
},
{
"id": 0,
"title": "OAS",
"description": null,
"owner": null,
"url": "https://support.example.com/en-ae",
"type": "External",
"rank": 0,
},
{
"id": 0,
"title": "OAS",
"description": null,
"owner": null,
"url": "https://support.example.com/en-al",
"type": "External",
"rank": 0,
}
Как видите, объект type
помогает мне различать все продукты в ответе API. Я хочу поставить фильтр на него, так как когда пользователь выбирает из выпадающего списка Внутренний, он будет отображать только внутренние продукты, а если пользователь выбирает Внешний, он будет отображать только внешние продукты.
То, что я пробовал до сих пор, ниже.
SearchActions
import {
SEARCH_PRODUCTS,
FETCH_PRODUCTS,
LOADING,
PAGINATE,
KEYWORD
} from "./types";
import axios from "axios";
import { results } from "./data/result";
import { store } from "../_helpers/store";
import { userService } from "../_services";
import { apiBaseUrl } from "../config.example";
const token = userService.getToken();
export const searchProduct = text => dispatch => {
dispatch({
type: SEARCH_PRODUCTS,
payload: text
});
};
export const fetchProducts = text => dispatch => {
console.log("Called from ", text);
const api = `/Search?searchString=${text}`;
axios
.get(apiBaseUrl + api, { headers: { Authorization: `Bearer ${token}` } })
.then(res => {
console.log("hello", api);
try {
dispatch({
type: FETCH_PRODUCTS,
payload: res
});
} catch (err) {
console.log("error", err);
}
});
};
export const saveKeyword = text => dispatch => {
const api = `/search/${text}`;
axios
.get(apiBaseUrl + api, { headers: { Authorization: `Bearer ${token}` } })
.then(res => {
console.log("Keyword Api called");
try {
dispatch({
type: KEYWORD,
payload: res
});
} catch (err) {
console.log("Error in Keyword", err);
}
});
};
export const paginate = currentPage => dispatch => {
dispatch({
type: PAGINATE,
payload: currentPage
});
dispatch(fetchProducts("paginate"));
};
export const setLoading = () => {
return {
type: LOADING
};
};
Searchbar.jsx
import React from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import {
searchProduct,
fetchProducts,
setLoading,
saveKeyword
} from "../../../_actions/search.action";
import Loader from "react-loader-spinner";
class SearchBar extends React.Component {
handleInputChange = e => {
e.preventDefault();
this.props.searchProduct(e.target.value);
};
onClick = e => {
console.log("I am " + this.props.text);
console.log("Search button clicked");
this.props.saveKeyword(this.props.text);
this.props.fetchProducts(this.props.text);
// this.props.setLoading();
};
render() {
const { text, loading } = this.props;
return (
<div className="s130">
<form
onSubmit={e => {
e.preventDefault();
}}
>
<div className="inner-form">
<div className="input-field first-wrap">
<div className="svg-wrapper">
<svg
xmlns="http://www.w3.org/2000/svg"
width="auto"
height="auto"
viewBox="0 0 24 24"
>
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z">
{" "}
</path>
</svg>
</div>
<input
id="search"
type="text"
value={text}
placeholder="What are you looking for?"
onChange={this.handleInputChange}
ref={input => (this.textInput = input)}
/>
</div>
<div className="input-field second-wrap">
<Link to={`/dashboard/search?q=${text}`}>
<button
className="btn-search"
type="button"
onClick={this.onClick}
>
{" "}
SEARCH{" "}
</button>
</Link>
</div>
{loading ? "Searching" : ""}
{this.pr}
</div>
</form>
</div>
);
}
}
const mapStateToProps = state => ({
text: state.product.text,
loading: state.product.loading
});
export default connect(mapStateToProps, {
searchProduct,
fetchProducts,
setLoading,
saveKeyword
})(SearchBar);
Search-results-container.jsx
import React from "react";
import queryString from "query-string";
import { connect } from "react-redux";
import SearchResult from "./search-results";
import { results } from "../../../_actions/data/result";
import Select from "react-select";
import "react-loader-spinner/dist/loader/css/react-spinner-loader.css";
import Loader from "react-loader-spinner";
import SearchBar from "./search-bar";
import { fetchProducts, searchProduct } from "../../../_actions/search.action";
import { useSelector, useDispatch } from "react-redux";
class SearchResultContainer extends React.Component {
componentDidMount() {
const query = queryString.parse(this.props.location.search).q;
console.log("Location Props", this.props.location.search);
this.props.searchProduct(query);
this.props.fetchProducts(query);
}
componentWillReceiveProps(nextProps) {
console.log("nextProps", nextProps);
// if (nextProps.query !== this.props.query) {
// this.setState({ query: nextProps.query });
// return this.searchRepositories(nextProps.query);
// }
}
render() {
const { loading } = this.props;
const str = this.props.location.search;
const res = str.split("?q=");
console.log("PROS", this.props);
const companies = [
{
label: "Internal",
value: "Internal"
},
{
label: "External",
value: "External"
];
return loading ? (
<div class="row"></div>
) : (
<React.Fragment>
<div className="row">
<div className="col-sm-2" />
<div className="col-sm-8">
<div class="container bootstrap snippet">
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-content">
<h2>We are Fetching:{res}</h2>
<small>
Request time (5-10 seconds): Please be patient, this may
take sometime, as we are gathering information
</small>
</div>
</div>
</div>
</div>
</div>
<SearchBar />
//For Internal and External
<Select options={Select}></Select>
<br></br>
<div class="row">
<Loader
type="ThreeDots"
color="#00BFFF"
height="100"
width="100"
timeout={2500}
></Loader>
<SearchResult />
</div>
</div>
<div className="col-sm-2" />
</div>
</React.Fragment>
);
}
}
const mapStateToProps = state => ({
loading: state.product.loading
});
export default connect(mapStateToProps, { searchProduct, fetchProducts })(
SearchResultContainer
);
search-results.jsx
import React from "react";
import { connect } from "react-redux";
import SingleSearchResult from "./single-search-result";
import { results } from "../../../_actions/data/result";
import "react-loader-spinner/dist/loader/css/react-spinner-loader.css";
import Loader from "react-loader-spinner";
import { useSelector, useDispatch } from "react-redux";
import { paginate } from "../../../_actions/search.action";
import Pagination from "./pagination";
import "./test.css";
class SearchResults extends React.Component {
// onChangePage = data => {
// this.setState({
// pageLimit: data.pageLimit,
// totalPages: data.totalPages,
// currentPage: data.page,
// startIndex: data.startIndex,
// endIndex: data.endIndex
// });
// };
render() {
const { products, pagination, paginate } = this.props;
return (
<React.Fragment>
{products.map(result => (
<SingleSearchResult result={result} />
))}
{/* <Pagination
totalRecords={products.length}
pageLimit={pageLimit || 2}
initialPage={1}
pagesToShow={5}
onChangePage={this.onChangePage}
/> */}
<div class="row">
<div class="center-block">
<Pagination
resultsPerPage={pagination.pageLimit}
totalResults={10}
paginate={paginate}
/>
</div>
</div>
</React.Fragment>
);
}
}
const mapStateToProps = state => ({
products: state.product.products,
pagination: state.product.pagination
});
export default connect(mapStateToProps, { paginate })(SearchResults);
и последние где все мои результаты поиска выглядят так:
singlesearchresult
import React, { useState, useEffect } from "react";
import Rating from "./rating";
import "./test.css";
import { Spinner, Collapse, Card, CardBody } from "reactstrap";
import { detailsProduct } from "../../../_actions/product.details.action";
import { ProductDetails, DoctorProductLocation } from "../../../locations";
import { Link, Redirect } from "react-router-dom";
import { setLoading } from "../../../_actions/search.action";
import Loader from "react-loader-spinner";
import Select from "react-select";
import { GoThumbsdown, GoThumbsup } from "react-icons/go";
import Footer from "../footer";
// import { fetchProducts } from "../../../_actions/search.action";
// import { detailsProduct } from "../../../_actions/product.details.action";
function onClickHandler(id) {
console.log("calling Details Product", id);
detailsProduct(id);
}
export default function SingleSearchResult(props) {
// console.log("PROPS FROM SINGLE SEARCH", props);
let result = props.result;
//Collapse For External
const [collapse, setCollapse] = useState(false);
const toggle = () => setCollapse(!collapse);
const loading = () => <Spinner color="success" />;
// console.log("SINGLE SEARCH PROPS RESULT", result);
// loading = () => <Spinner color="success" />;
{
/* <Loader
type="ThreeDots"npm
color="#00BFFF"
height="100"
width="100"
timeout={1000}
></Loader> */
}
console.log("Length", result.title.slice(0, 3));
return (
<div className="row">
<div className="s130">
{/* <div class="col-lg-8 col-xs-8 col-sm-12 col-md-7"> */}
<div className="col-lg">
<div className="container">
<div className=""></div>
{/* Loader Here ibox-content*/}
{result.type === "Internal" ? (
<Link
value={result.productid}
to={DoctorProductLocation.path}
onClick={() => onClickHandler(result.productid)}
//onClickHandler(result.productid)
>
<h3 style={{ color: "#1a0dab" }}>
{result.title}
<hr></hr>
</h3>
</Link>
) : (
//Try With OnClick Function
<a onClick={toggle} target="_blank">
<h3 style={{ color: "RED" }}>
{result.title}
<hr></hr>
</h3>
</a>
)}
<p className="p1">{result.description}</p>
{/* //href={result.url} */}
{/* {result.type == "Article" ? <p>by {result.author}</p> : ""} */}
{/* <Rating rating={result.rating} /> */}
</div>
{/* <a
href={result.url}
target={result.url === "External" ? "_blank" : ""}
// data-toggle="modal"
// data-target="#aripiprazol"
>
{" "}
<cite class="iUh30">{result.url}</cite>
<br />
</a> */}
{result.type === "Internal" ? (
<Link
className="iUh30"
to={DoctorProductLocation.path}
onClick={() => onClickHandler(result.productid)}
>
{/* <a className="iUh30">{result.url}</a> */}
{/* <p>DDH PRODUCT</p> */}
</Link>
) : (
//Try With OnClick Function
<Collapse isOpen={collapse}>
<Card style={{ maxWidth: "100%" }}>
<CardBody>
Source:
<a className="iUh30" href={result.url} target="_blank">
<a>{result.url}</a>
</a>
</CardBody>
</Card>
<Card style={{ maxWidth: "100%" }}>
<CardBody>
<a
href={result.url + "subscribe"}
style={{ color: "#1a0dab" }}
target="_blank"
>
Subscribe
</a>
<p>{result.description} </p>
</CardBody>
<div className="row">
<GoThumbsup className="col-6"></GoThumbsup>
<GoThumbsdown className="col-6"></GoThumbsdown>
</div>
</Card>
<br></br>
</Collapse>
)}
{/* RANKING */}
{/* <p className="rank">Visited {result.rank} times</p> */}
</div>
</div>
</div>
);
}
Как вы можете видеть выше в search-result-container.jsx Я пытался использовать библиотеку реагировать на выбор для раскрывающегося списка, а затем для ответа, но я не имею ни малейшего представления о том, как я могу это сделать.