reactjs - React JS - 如何在 enter 或 keydown 上提交表单
问题描述
我有一个简单的 React JS 应用程序,我想在其中添加搜索功能。我创建了搜索函数代码并添加了搜索组件(来自 Semantic-UI),它将搜索到的值传递给函数。
如何让它从下面的搜索组件调用函数来触发表单提交?
这是搜索组件。
<Search
onSearchChange={(e) => this.handleSearchChangeNew(e.target.value)}
/>
这是搜索功能:
async handleSearchChangeNew (value) {
console.log("value in new search: " + value)
this.props.updateSearchString(value);
fetch(`api/license/search/${JSON.stringify(this.props.searchString)}`, {
credentials: 'include'})
.then(response => response.json())
.then(data => this.setState({
licenses: data,
isLoading: false,
licensePage: data.slice(this.state.begin, this.state.end)
}))
.catch(() => this.props.history.push('/'));
}
上面的函数打印从搜索框传递的值。
我之前组装了一个有点不雅的搜索功能,其中输入被键入到一个文本框中,并且通过按下“搜索”提交功能来调用上述搜索功能。该搜索功能将根据输入框中的内容重新填充页面。它仍然在那里,但我还添加了上面显示的新搜索功能代码。
作为参考,这是整个课程。
import React, { Component } from 'react';
import { Button, ButtonGroup, Container, Table } from 'reactstrap';
import { Pagination, Search } from 'semantic-ui-react'
import AppNavbar from './AppNavbar';
import { Link, withRouter } from 'react-router-dom';
import { instanceOf } from 'prop-types';
import { withCookies, Cookies } from 'react-cookie';
class LicenseList extends Component {
static propTypes = {
cookies: instanceOf(Cookies).isRequired
};
constructor(props) {
super(props);
const {cookies} = props;
this.state = {
word: '',
newWord: '',
licenses: [],
licensePage: [],
csrfToken: cookies.get('XSRF-TOKEN'),
isLoading: true,
licensesPerPage: 7,
activePage: 1,
begin: 0,
end: 7
};
this.remove = this.remove.bind(this);
this.btnClick = this.btnClick.bind(this);
this.handleSearchChangeNew = this.handleSearchChangeNew.bind(this);
}
componentDidMount() {
this.setState({isLoading: true});
console.log("searchString: " + this.props.searchString);
fetch(`/api/license/search/${this.props.searchString}`, {credentials: 'include'})
.then(response => response.json())
.then(data => this.setState({
licenses: data,
isLoading: false,
licensePage: data.slice(this.state.begin, this.state.end)
}))
.catch(() => this.props.history.push('/'));
}
async handleSearchChange(value) {
this.props.updateSearchString(value)
}
async searchFromString () {
this.setState({isLoading: true});
fetch(`api/license/search/${this.props.searchString}`, {
credentials: 'include'})
.then(response => response.json())
.then(data => this.setState({
licenses: data,
isLoading: false,
licensePage: data.slice(this.state.begin, this.state.end)
}))
.catch(() => this.props.history.push('/'));
}
async clearSearchString(value) {
this.props.updateSearchString('');
}
async btnClick(
event: React.MouseEvent<HTMLAnchorElement>,
data: PaginationProps
) {
await this.setState({activePage: data.activePage});
await this.setState({begin: this.state.activePage * this.state.licensesPerPage - this.state.licensesPerPage});
await this.setState({end: this.state.activePage *this.state.licensesPerPage});
this.setState({
licensePage: this.state.licenses.slice(this.state.begin, this.state.end),
});
}
async remove(id) {
if (window.confirm('Are you sure you wish to delete this license?')) {
await fetch(`/api/license/${id}`, {
method: 'DELETE',
headers: {
'X-XSRF-TOKEN': this.state.csrfToken,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
credentials: 'include'
}).then(() => {
let updatedLicenses = [...this.state.licenses].filter(i => i.id !== id);
this.setState({licenses: updatedLicenses});
});
}
}
download(url) {
// fake server request, getting the file url as response
setTimeout(() => {
const response = {
file: url,
};
// server sent the url to the file!
// now, let's download:
window.open(response.file);
// you could also do:
// window.location.href = response.file;
}, 100);
}
async handleSearchChangeNewx(value) {
this.props.updateSearchString(value);
}
async handleSearchChangeNew (value) {
console.log("value in new search: " + value)
this.props.updateSearchString(value);
fetch(`api/license/search/${JSON.stringify(this.props.searchString)}`, {
credentials: 'include'})
.then(response => response.json())
.then(data => this.setState({
licenses: data,
isLoading: false,
licensePage: data.slice(this.state.begin, this.state.end)
}))
.catch(() => this.props.history.push('/'));
}
render() {
const {licensePage, activePage } = this.state;
const {licenses, isLoading, licensesPerPage} = this.state;
const totalPages = Math.ceil(licenses.length / licensesPerPage);
if (isLoading) {
return <p>Loading...</p>;
}
const licenseList = licensePage.map(license => {
return<tr key={license.id}>
<td style={{whiteSpace: 'nowrap'}}>{license.fullName}</td>
<td style={{whiteSpace: 'nowrap'}}>{license.requester}</td>
<td style={{whiteSpace: 'nowrap'}}>{license.tag}</td>
<td style={{whiteSpace: 'nowrap'}}>{license.dateCreated.substring(0, 10)}</td>
<td style={{whiteSpace: 'nowrap'}}>{license.expiration}</td>
<td style={{whiteSpace: 'nowrap'}}>{license.systems}</td>
<td>
<ButtonGroup>
<Button size="sm" color="primary" tag={Link} to={"/licenses/" + license.id}>Edit</Button>
<Button size="sm" color="dark" onClick={() => this.download(license.url)}>Download</Button>
<Button size="sm" color="danger" onClick={() => this.remove(license.id)}>Delete</Button>
</ButtonGroup>
</td>
</tr>
});
return (
<div>
<AppNavbar/>
<Container fluid>
<h3>License List</h3>
<div className="float-left">
<div>
<input type="text" value={this.props.searchString} onChange={(e) => this.props.updateSearchString(e.target.value)} />
<input type="submit" value="Search" onClick={() => this.searchFromString()} />
<input type="submit" value="Clear Search" onClick={() => this.clearSearchString()} />
<Search
onSearchChange={(e) => this.handleSearchChangeNew(e.target.value)}
/>
</div>
</div>
<div className="float-right">
<Button color="primary" tag={Link} to="/licenses/new">Create License</Button>
</div>
<Table className="mt-4">
<thead>
<tr>
<th width="10%">Full Name</th>
<th width="5%">Requester</th>
<th width="10%">Tag</th>
<th width="5%">Created</th>
<th width="5%">Expiration</th>
<th width="5%">Systems</th>
<th width="10%">Actions</th>
</tr>
</thead>
<tbody>
{licenseList}
</tbody>
</Table>
<div>
</div>
<div className="col text-center">
<Pagination
activePage={activePage}
onPageChange={this.btnClick}
totalPages={totalPages}
ellipsisItem={null}
/>
</div>
</Container>
</div>
);
}
}
export default withCookies(withRouter(LicenseList));
解决方案
使用本机<form>
元素,一切顺利!浏览器将完成艰巨的任务。将您的输入包装在 a<form>
而不是 a 中<div>
,并将您的实际表单提交处理程序传递给onSubmit
listener on <form onSubmit={this.handleSearchChangeNew}>
。那么你需要一个event.preventDefault()
来防止页面刷新;不过,给你的输入 aname
也是一个很好的做法。<form>
element 将进行基本验证,并处理回车键;
同时,如果您不习惯使用<form>
,您也可以自己处理按键更改事件(就像您处理大多数原生<form>
功能一样);keyDown
在您的表单逻辑所在的父 html 元素上添加一个事件侦听器;然后处理enter
关键代码。
function (event) {
if (event.which == 13 || event.keyCode == 13) {
// enter key had been pressed
// submit
}
};
编辑:如何手动处理keydown:
<div onKeyDown={(e)=>console.log(e.keyCode)}>
<input .... />
<input .... />
<Search onSearchChange={(e) => this.handleSearchChangeNew(e.target.value)} />
</div>
推荐阅读
- python - PyTorch 何时自动转换 Tensor dtype?
- protractor - protractorJS chai - 如何使用 getText() 断言数组中元素的文本包含字符串?
- load-testing - Liquibase:在这种情况下如何将我的数据库恢复到以前的状态
- java - 等待两个异步 firebase ml 视觉方法结果以在第三种方法中使用它们的最佳方法
- c++ - 使用 boost::geometry::within 编译错误
- reactjs - 反应网络应用程序条件应用程序加载不起作用
- vue.js - 在 Vue 项目中使用 `chromatic-sass`(或在 Sass 文件/块中使用任何 JavaScript 函数)
- java - 如何在 GWT Web 应用程序中正确实现 DAO?
- ruby-on-rails - Rails 5 中的自引用关联
- android - 从 RecyclerView onClick 获取数据绑定项