当前,我有一个搜索栏,用于切换formSubmit上的“结果”组件。 我正在寻找一种React方法来处理“结果”外部的clicks()以隐藏它。 问题是当我转到另一个页面或单击任何地方时,我的“结果”一直显示。
我已经尝试过使用诸如focusOutside之类的CSS东西,但这不是我的方式。
Search.js
import React, {Component} from 'react';
import {Container, Icon} from 'semantic-ui-react';
import {connect} from 'react-redux';
import {searchAll} from './modules/searchAction';
import SearchResult from './SearchResult';
import MyLoader from "../../components/MyLoader";
import "../../styles/layout/_search.scss"
class Search extends Component {
state = {
query: null,
};
handleInputChange = (e) => {
this.setState({query: e.target.value})
};
handleSubmit = (e) => {
e.preventDefault();
this.state.query === null || undefined || '' ?
(alert('wrong input')) :
(this.props.searchAll(this.state.query));
};
render() {
const {error, loading, result} = this.props;
const filteredResult = result.filter(item => item.poster_path && (item.name || item.title));
if (error) {
console.log(error);
}
if (loading) {
return <MyLoader/>;
}
return (
<div className="search_area">
<Container className="primary-container">
<form className='search_form' onSubmit={this.handleSubmit}>
<Icon name='search'
size="large"
className='search_icon'/>
<input type='text'
className='search_input'
placeholder="Search for a Movie, Tv Show or Person"
onChange={this.handleInputChange}/>
</form>
<div className="results_area">
{filteredResult.map(suggestion => {
return (
<SearchResult
key={suggestion.id}
title={suggestion.title}
name={suggestion.name}
release_date={suggestion.release_date}
media_type={suggestion.media_type}
path={suggestion.poster_path}
/>
)
})}
</div>
</Container>
</div>
)
};
}
const mapStateToProps = state => ({
result: state.suggestions.suggestions,
loading: state.suggestions.loading,
error: state.suggestions.error
});
const mapDispatchToProps = {
searchAll,
};
export default connect(mapStateToProps, mapDispatchToProps)(Search);
SearchResult.js
import React from "react";
import {DEFAULT_IMG_URL} from "../../const";
import {SMALL_IMG} from "../../const";
import {Image} from "semantic-ui-react";
import "../../styles/layout/_search.scss"
const SearchResult = (props) => {
let title = null;
let release = null;
let type = null;
let imageLink = DEFAULT_IMG_URL + SMALL_IMG + props.path;
switch (props.media_type) {
case "movie": {
type = "Movie";
break;
}
case "tv": {
type = "TV";
break;
}
case "person": {
type = "Person";
break;
}
default: {
type = "TBD";
break;
}
}
props.title === undefined ?
(title = "N/A"):
(title = props.title);
props.release_date === undefined ?
(release = "N/A"):
(release = props.release_date);
return (
<div className="suggestion-body">
<Image className="suggestion-image"
src={imageLink}>
</Image>
<div className="suggestion-info">
<div className="suggestion-title">
<h2>{title}</h2>
</div>
<div className="suggestion-year">
<h4>{release}</h4>
</div>
</div>
<div className="suggestion-type">
{type}
</div>
</div>
);
};
export default SearchResult;
searchReducer.js
import {
SEARCH_ALL_BEGIN,
SEARCH_ALL_SUCCESS,
SEARCH_ALL_FAILURE
} from "./searchAction";
const initialState = {
suggestions: [],
loading: false,
error: null
//suggestions true/false
};
const searchReducer = (state = initialState, action) => {
switch(action.type) {
case SEARCH_ALL_BEGIN:
return {
...state,
loading: true,
error: null
};
case SEARCH_ALL_SUCCESS:
return {
...state,
loading: false,
suggestions: action.suggestions
};
case SEARCH_ALL_FAILURE:
return {
...state,
loading: false,
error: action.error,
};
default:
return state;
}
};
export default searchReducer;
和searchAction.js
import axios from 'axios/index';
import {KEY} from "../../../key";
import {DEFAULT_URL} from "../../../const";
export const SEARCH_ALL_BEGIN = 'SEARCH_ALL_BEGIN';
export const SEARCH_ALL_SUCCESS = 'SEARCH_ALL_SUCCESS';
export const SEARCH_ALL_FAILURE = 'SEARCH_ALL_FAILURE';
export const searchAllBegin = () => ({
type: SEARCH_ALL_BEGIN
});
export const searchAllSuccess = suggestions => ({
type: SEARCH_ALL_SUCCESS,
suggestions
});
export const searchAllFailure = error => ({
type: SEARCH_ALL_FAILURE,
error
});
export const searchAll = (query) => {
return dispatch => {
let url = DEFAULT_URL + `search/multi?api_key=` + KEY + `&language=en-US&query=` + query + `&page=1&include_adult=false`;
dispatch(searchAllBegin());
axios.get(url)
.then(result => {
dispatch(searchAllSuccess(result.data.results));
})
.catch(error => dispatch(searchAllFailure()));
};
};
正如我所见,我的行为仅给我两个解决方案,一个是隐藏元素,第二个是发送空查询,这对我来说没有意义,应该有更好的方法吗?
答案 0 :(得分:0)
您可以在componentDidMount钩子上单击到body元素时注册EventListener。 Сheck外部单击,不要忘记删除componentWillUnmount钩子上的EventListener。
答案 1 :(得分:0)
您可以在搜索框周围放置一个叠加层,如下所示:
// style
.overlay {
background-color: transparent;
width: 100%;
height: 100%;
top: 0;
left: 0;
position: absolute;
z-index: 1200;
}
close(e) {
// this is necesary to no close if the search box is clicked
if (e && e.target !== e.currentTarget) {
return;
}
// my close stuff
}
render() {
return <div className="overlay" style={{height: document.body.scrollHeight}}
onClick={e => this.close(e)}>
<div className="searchbox">
My searchbox stuff...
</div>
</div>
}
答案 2 :(得分:0)
我已经通过两个步骤解决了这个问题,首先是将[https://github.com/airbnb/react-outside-click-handler]添加到我的项目中,然后添加一个isSearchResultsVisible
bool变量。
Search.js文件
import React, {Component} from 'react';
import {Container, Icon} from 'semantic-ui-react';
import {connect} from 'react-redux';
import {searchAll, setSearchResultsVisibility} from './modules/searchAction';
import SearchResult from './SearchResult';
import MyLoader from "../../components/MyLoader";
import "../../styles/layout/_search.scss"
class Search extends Component {
state = {
query: null,
};
handleInputChange = (e) => {
this.setState({query: e.target.value})
};
handleSubmit = (e) => {
e.preventDefault();
if(this.state.query) {
this.props.searchAll(this.state.query);
this.props.setSearchResultsVisibility(true);
}
};
render() {
const {error, loading, result, isSearchResultsVisible} = this.props;
const filteredResult = result.filter(item => item.poster_path && (item.name || item.title));
if (error) {console.log(error)}
if (loading) {return <MyLoader/>}
return (
<div className="search_area">
<Container className="primary-container">
<form className="search_form" onSubmit={this.handleSubmit}>
<Icon name="search"
size="large"
className="search_icon"
/>
<input type="text"
className="search_input"
placeholder="Search for a Movie, Tv Show or Person"
onChange={this.handleInputChange}
/>
</form>
{
isSearchResultsVisible &&
<SearchResult result={filteredResult} />
}
</Container>
</div>
)
};
}
const mapStateToProps = state => ({
result: state.suggestions.suggestions,
loading: state.suggestions.loading,
error: state.suggestions.error,
isSearchResultsVisible: state.suggestions.isSearchResultsVisible,
});
const mapDispatchToProps = {
searchAll,
setSearchResultsVisibility,
};
export default connect(mapStateToProps, mapDispatchToProps)(Search);
添加
export const SET_SEARCH_RESULTS_VISIBILITY = 'SET_SEARCH_RESULTS_VISIBILITY';
export const setSearchResultsVisibility = isSearchResultsVisible => ({
type: SET_SEARCH_RESULTS_VISIBILITY,
isSearchResultsVisible
});
操作文件和
case SET_SEARCH_RESULTS_VISIBILITY:
return {
...state,
isSearchResultsVisible: action.isSearchResultsVisible,
};
减速器。
如果有人正在阅读此书,请不要忘记将SET_SEARCH_RESULTS_VISIBILITY
导入reducer并将isSearchResultsVisible: false,
添加到initialState