30天入坑React ---------------day10 Interactivity
這篇文章是系列的一部分 。
在本系列中,我們將從非常基礎開始,逐步瞭解您需要了解的所有內容,以便開始使用React。如果您曾經想學習React,那麼這裡就是您的最佳選擇!
互動
今天,我們將介紹如何為我們的應用程式新增互動性,使其具有吸引力和動態性。
通過這一點,我們構建了少數幾個元件,而沒有增加太多的使用者互動。今天,我們要改變這一點。
使用者互動
瀏覽器是一個事件驅動的應用程式。使用者在瀏覽器中執行的所有操作都會觸發事件,從單擊按鈕到甚至只是移動滑鼠。在純的JavaScript中,我們可以監聽這些事件並附加的JavaScript函式來與它們進行互動。
例如,可以我們mousemove
export const go = () => { const ele = document.getElementById('mousemove'); ele.innerHTML = 'Move your mouse to see the demo'; ele.addEventListener('mousemove', function(evt) { const { screenX, screenY } = evt; ele.innerHTML = '<div>Mouse is at: X: ' + screenX + ', Y: ' + screenY + '</div>'; }) }
這導致以下功能:
移動滑鼠以檢視演示
在陣營中,我們不必在原始的JavaScript中與瀏覽器的事件迴圈互動,因為陣營為我們提供了一種處理事件的方法props
。
例如,mousemove
要從React上面的(相當不起眼的)演示中監聽事件,我們將設定prop onMouseMove
(注意事件名稱的camelcasing)。
<div onMouseMove={(evt) => console.log(evt)}>
Move the mouse over this text
</div>
反應了提供很多最props
我們可以設定來監聽不同的瀏覽器事件,例如點選,觸控,拖動,滾動,選擇事件等等(參閱請
要檢視其中的一些實際操作,的英文以下props
我們可以傳遞給我們的元素的一些小_ECSHOP演示。列表中的每個文字元素都會設定它列出的道具。嘗試使用列表並檢視在元素中如何呼叫和處理事件(所有事件都在文字上設定,而不是列表項):
將我們在onClick
整個應用程式中使用支柱相當多,所以熟悉它是個好主意。在我們的活動列表標題中,我們有一個搜尋圖示,我們還沒有連線到顯示搜尋框。
我們想要的互動的英文<input />
在使用者點選搜尋圖示種植時顯示搜尋。回想一下,的我們Header
元件的英文這樣實現的:
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {
searchVisible: false
}
}
// toggle visibility when run on the state
showSearch() {
this.setState({
searchVisible: !this.state.searchVisible
})
}
render() {
// Classes to add to the <input /> element
let searchInputClasses = ["searchInput"];
// Update the class array if the state is visible
if (this.state.searchVisible) {
searchInputClasses.push("active");
}
return (
<div className="header">
<div className="menuIcon">
<div className="dashTop"></div>
<div className="dashBottom"></div>
<div className="circle"></div>
</div>
<span className="title">
{this.props.title}
</span>
<input
type="text"
className={searchInputClasses.join(' ')}
placeholder="Search ..." />
{/* Adding an onClick handler to call the showSearch button */}
<div
onClick={this.showSearch.bind(this)}
className="fa fa-search searchIcon"></div>
</div>
)
}
}
使用者當單擊該<div className="fa fa-search searchIcon"></div>
元素時,我們將要執行一個函式來更新元件的狀態,以便searchInputClasses
更新物件。使用onClick
處理程式,這非常簡單。
讓我們使這個元件有狀態(它需要跟蹤搜尋欄位是否應該顯示)。我們可以使用constructor()
函式將我們的元件轉換為有狀態:
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {
searchVisible: false
}
}
// ...
}
的英文什麼
constructor
功能?在JavaScript的中,該
constructor
函式的英文在建立³³物件時執行的函式。它返回對建立例項的物件函式的引用prototype
。簡單來說,建構函式是在JavaScript的執行時建立新物件時執行的函式。我們將使用建構函式方法在物件上設定例項變數,因為它在建立物件時正確執行。
使用
ES6
類語法建立³³物件時,必須我們super()
在任何其他方法之前呼叫該方法。呼叫該super()
函式呼叫父類的constructor()
函式。我們將使用相同的引數呼叫它,我們因為呼叫constructor()
了類的函式。
當用戶單擊該按鈕時,將我們要更新狀態以表示該searchVisible
標誌已更新。由於我們希望使用者能夠在<input />
第二次單擊搜尋圖示種植後關閉/隱藏欄位,因此將我們e月刊狀態而不是將其設定為真。
讓我們建立這個方法來繫結我們的單擊事件:
class Header extends React.Component {
// ...
showSearch() {
this.setState({
searchVisible: !this.state.searchVisible
})
}
// ...
}
最後,我們可以onClick
在icon元素上附加一個單擊處理程式(使用prop)來呼叫我們的新showSearch()
方法。我們Header
元件的整個更新原始碼如下所示:
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {
searchVisible: false
}
}
// toggle visibility when run on the state
showSearch() {
this.setState({
searchVisible: !this.state.searchVisible
})
}
render() {
// Classes to add to the <input /> element
let searchInputClasses = ["searchInput"];
// Update the class array if the state is visible
if (this.state.searchVisible) {
searchInputClasses.push("active");
}
return (
<div className="header">
<div className="fa fa-more"></div>
<span className="title">
{this.props.title}
</span>
<input
type="text"
className={searchInputClasses.join(' ')}
placeholder="Search ..." />
{/* Adding an onClick handler to call the showSearch button */}
<div
onClick={this.showSearch.bind(this)}
className="fa fa-search searchIcon"></div>
</div>
)
}
}
嘗試單擊搜尋圖示並觀察輸入欄位的顯示和消失(動畫效果由CSS動畫處理)。
輸入事件
每當我們在React中構建表單時,我們將使用React提供的輸入事件。最值得注意的是,我們最常使用onSubmit()
和onChange()
道具。
讓我們更新我們的搜尋框演示,以便在更新時捕獲搜尋欄位內的文字。每當一個<input />
欄位具有onChange()
prop設定時,它將在每次欄位改變時呼叫該函式。當我們點選它並開始輸入時,將呼叫該函式。
使用此prop,我們可以捕獲我們州的欄位值。
我們不是更新我們的<Header />
元件,而是建立一個包含<form />
元素的新子元件。通過將表單處理職責移動到它自己的表單,我們可以簡化<Header />
程式碼,當我們的使用者提交表單時,我們可以呼叫標題的父級(這是通常的React模式)。
讓我們建立一個我們稱之為的新元件SearchForm
。這個新元件是一個有狀態元件,因為我們需要保持搜尋輸入的值(跟蹤它的變化):
class SearchForm extends React.Component {
// ...
constructor(props) {
super(props);
this.state = {
searchText: ''
}
}
// ...
}
現在,我們已經在<Header />
元件中編寫了表單的HTML ,所以讓我們從Header
元件中獲取它並從我們的SearchForm.render()
函式返回它:
class SearchForm extends React.Component {
// ...
render() {
const { searchVisible } = this.state;
let searchClasses = ['searchInput']
if (searchVisible) {
searchClasses.push('active')
}
return (
<form className='header'>
<input
type="search"
className={searchClasses.join(' ')}
onChange={this.updateSearchInput.bind(this)}
placeholder="Search ..." />
<div
onClick={this.showSearch.bind(this)}
className="fa fa-search searchIcon"></div>
</form>
);
}
}
請注意,我們在我們的<input />
領域丟失了樣式。由於我們searchVisible
的新元件中不再具有狀態,因此我們不能再使用它來設定樣式<input />
。但是,我們可以從我們的Header
元件傳遞一個prop,它告訴SearchForm
將輸入呈現為可見。
讓我們定義searchVisible
prop(PropTypes
當然使用)並更新render
函式以使用新的prop值來顯示(或隱藏)搜尋<input />
。我們還將欄位可見性的預設值設定為false(因為我們的Header
顯示/隱藏它很好):
class SearchForm extends React.Component {
static propTypes = {
onSubmit: PropTypes.func.isRequired,
searchVisible: PropTypes.bool
}
// ...
}
現在我們將樣式返回到<input />
元素上,讓我們新增使用者在搜尋框中鍵入的功能,我們將要捕獲搜尋欄位的值。我們可以通過將onChange
prop新增到<input />
元素並向其傳遞函式來實現此工作流程,以便每次<input />
更改元素時呼叫它。
class SearchForm extends React.Component {
// ...
updateSearchInput(e) {
const val = e.target.value;
this.setState({
searchText: val
});
}
// ...
render() {
const { searchVisible } = this.state;
let searchClasses = ['searchInput']
if (searchVisible) {
searchClasses.push('active')
}
return (
<form className='header'>
<input
type="search"
className={searchClasses.join(' ')}
onChange={this.updateSearchInput.bind(this)}
placeholder="Search ..." />
<div
onClick={this.showSearch.bind(this)}
className="fa fa-search searchIcon"></div>
</form>
);
}
}
當我們輸入欄位時,updateSearchInput()
將呼叫該函式。我們將通過更新狀態來跟蹤表單的價值。在updateSearchInput()
函式中,我們可以直接呼叫this.setState()
以更新元件的狀態。
該值儲存在
event
物件的目標上event.target.value
。
class SearchForm extends React.Component {
// ...
updateSearchInput(e) {
const val = e.target.value;
this.setState({
searchText: val
});
}
// ...
}
受控制與不受控制
我們正在建立所謂的不受控制的元件,因為我們沒有設定
<input />
元素的值。我們現在無法對輸入文字值進行任何驗證或後處理。如果我們想要驗證欄位或操縱
<input />
元件的值,我們必須建立所謂的受控元件,這實際上只意味著我們使用value
prop 傳遞一個值。受控元件版本的render()
功能如下所示:class SearchForm extends React.Component { render() { return ( <input type="search" value={this.state.searchText} className={searchInputClasses} onChange={this.updateSearchInput.bind(this)} placeholder="Search ..." /> ); } }
截至目前,我們無法實際提交表單,因此我們的使用者無法真正搜尋。讓我們改變這一點。我們要將<input />
元件包裝在<form />
DOM元素中,以便我們的使用者可以按回車鍵提交表單。我們可以通過使用元素onSubmit
上的prop 來捕獲表單提交<form />
。
讓我們更新render()
函式以反映這一變化。
class SearchForm extends React.Component {
// ...
submitForm(e) {
e.preventDefault();
const {searchText} = this.state;
this.props.onSubmit(searchText);
}
// ...
render() {
const { searchVisible } = this.props;
let searchClasses = ['searchInput']
if (searchVisible) {
searchClasses.push('active')
}
return (
<form onSubmit={this.submitForm.bind(this)}>
<input
type="search"
className={searchClasses.join(' ')}
onChange={this.updateSearchInput.bind(this)}
placeholder="Search ..." />
</form>
);
}
}
我們馬上打電話
event.preventDefault()
給這個submitForm()
功能。這會阻止瀏覽器冒泡事件,這會導致整個頁面的預設行為重新載入(瀏覽器提交表單時的預設功能)。
現在,當我們輸入<input />
欄位並按Enter鍵時,將submitForm()
使用事件物件呼叫該函式。
所以...很好,我們可以提交表格和內容,但我們什麼時候才能進行搜尋?出於演示的目的,現在,我們會通過搜尋文字了親子部分構成的鏈,因此Header
可以決定什麼搜尋。
該
SearchForm
元件當然不知道它在搜尋什麼,所以我們必須將責任傳遞給鏈。我們將使用這個回撥策略。
為了將搜尋功能傳遞給鏈,我們SearchForm
需要接受一個支柱函式來在提交表單時呼叫。讓我們定義一個我們稱之為onSubmit
可以傳遞給我們SearchForm
元件的道具。作為優秀的開發人員,還將我們為此功能新增預設prop
值和a 。由於我們要確保定義,我們將把道具設定為必需的道具:propType
onSubmit
onSubmit()
onSubmit
class SearchForm extends React.Component {
static propTypes = {
onSubmit: PropTypes.func.isRequired,
searchVisible: PropTypes.bool
}
// ...
static defaultProps = {
onSubmit: () => {},
searchVisible: false
}
// ...
}
提交表單時,我們可以直接從中呼叫此函式props
。由於我們在狀態中跟蹤搜尋文字,可以我們使用searchText
狀態中的值呼叫函式,因此onSubmit()
函式只獲取值而不需要處理事件。
class SearchForm extends React.Component {
// ...
submitForm(event) {
// prevent the form from reloading the entire page
event.preventDefault();
// call the callback with the search value
this.props.onSubmit(this.state.searchText);
}
}
現在,當用戶按下回車鍵時,可以我們通過我們的元件呼叫此onSubmit()
函式。props
Header
可以我們SearchForm
在元件中使用這個元件,Header
並將它們傳遞給我們定義的兩個道具(searchVisible
和onSubmit
):
import React from 'react';
import SearchForm from './SearchFormWithSubmit'
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {
searchVisible: false
}
}
// toggle visibility when run on the state
showSearch() {
this.setState({
searchVisible: !this.state.searchVisible
})
}
render() {
// Classes to add to the <input /> element
let searchInputClasses = ["searchInput"];
// Update the class array if the state is visible
if (this.state.searchVisible) {
searchInputClasses.push("active");
}
return (
<div className="header">
<div className="menuIcon">
<div className="dashTop"></div>
<div className="dashBottom"></div>
<div className="circle"></div>
</div>
<span className="title">
{this.props.title}
</span>
<SearchForm
searchVisible={this.state.searchVisible}
onSubmit={this.props.onSubmit} />
{/* Adding an onClick handler to call the showSearch button */}
<div
onClick={this.showSearch.bind(this)}
className="fa fa-search searchIcon"></div>
</div>
)
}
}
export default Header
現在我們有一個搜尋表單元件,可以我們在我們的應用程式中使用狀語從句:重用當然,我們實際上還沒有搜尋任何東西。讓我們解決這個問題並實施搜尋。
實施搜尋
要在我們的元件中實現搜尋,需要我們搜尋將職責從我們的Header
元件再次傳遞給我們將呼叫的容器元件Panel
。
首先,我們讓實現從子Panel
容器中的容器到Header
元件的回撥到父元件的相同模式。
在Header
元件上,我們讓更新propTypes
一個我們將定義為支柱的道具onSearch
:
class Header extends React.Component {
// ...
}
Header.propTypes = {
onSearch: PropTypes.func
}
在Header
元件的'submitForm()'函式內部,呼叫此onSearch()
丙我們將傳遞給它:
class Header extends React.Component {
// ...
submitForm(val) {
this.props.onSearch(val);
}
// ...
}
Header.propTypes = {
onSearch: PropTypes.func
}
請注意,我們的虛擬樹看起來像這樣:
<Panel> <Header> <SearchForm></SearchForm> </Header> </Panel
當
<SearchForm />
更新時,它會傳遞它對搜尋輸入對其父級的更改的感知<Header />
,它將當向上網站傳遞給<Panel />
元件時,此方法在作出反應程式應用中非常常見,併為我們的元件提供了一組良好的功能隔離。
回到Panel
我們在第7構建天的元件中,將我們函式傳遞給Header
作為onSearch()
支柱的函式Header
。我們在這裡說的是,當提交搜尋表單時,我們希望搜尋表單回撥到標題元件,呼叫然後Panel
元件來處理搜尋。
由於Header
元件不控制內容列表,Panel
元件確實如此,我們必須將責任再提高一級,正如我們在此定義的那樣。
無論如何,的我們Panel
元件基本上的英文Content
我們之前處理過的元件的副本:
class Panel extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false, // <~ set loading to false
activities: data,
filtered: data,
}
}
componentDidMount() {this.updateData();}
componentWillReceiveProps(nextProps) {
// Check to see if the requestRefresh prop has changed
if (nextProps.requestRefresh !== this.props.requestRefresh) {
this.setState({loading: true}, this.updateData);
}
}
handleSearch = txt => {
if (txt === '') {
this.setState({
filtered: this.state.activities
})
} else {
const { activities } = this.state
const filtered = activities.filter(a => a.actor && a.actor.login.match(txt))
this.setState({
filtered
})
}
}
// Call out to github and refresh directory
updateData() {
this.setState({
loading: false,
activities: data
}, this.props.onComponentRefresh);
}
render() {
const {loading, filtered} = this.state;
return (
<div>
<Header
onSubmit={this.handleSearch}
title="Github activity" />
<div className="content">
<div className="line"></div>
{/* Show loading message if loading */}
{loading && <div>Loading</div>}
{/* Timeline item */}
{filtered.map((activity) => (
<ActivityItem
key={activity.id}
activity={activity} />
))}
</div>
</div>
)
}
}
我們讓我們更新的狀態以所有遊戲一個searchFilter
字串,它只是搜尋值:
class Panel extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
searchFilter: '',
activities: []
}
}
}
為了實際處理搜尋,我們需要將一個onSearch()
函式傳遞給我們的Header
元件。讓我們onSearch()
在Panel
元件中定義一個函式,並將其傳遞給函式中的Header
道具render()
:
class Panel extends React.Component {
// ...
// after the content has refreshed, we want to
// reset the loading variable
onComponentRefresh() {this.setState({loading: false});}
handleSearch(val) {
// handle search here
}
render() {
const {loading} = this.state;
return (
<div>
<Header
onSearch={this.handleSearch.bind(this)}
title="Github activity" />
<Content
requestRefresh={loading}
onComponentRefresh={this.onComponentRefresh.bind(this)}
fetchData={this.updateData.bind(this)} />
</div>
)
}
}
在我們這裡所做的就是新增一個handleSearch()
函式並將其傳遞給標題。現在,當用戶在搜尋框中鍵入時,將handleSearch()
呼叫我們Panel
元件上的函式。
實際要實現搜尋,需要我們跟蹤此字串並更新我們的updateData()
功能以考慮搜尋過濾。首先,我們讓設定searchFilter
狀態。我們還可以Content
通過設定loading
為真來強制重新載入資料,因此我們可以一步完成:
class Panel extends React.Component {
// ...
handleSearch(val) {
this.setState({
searchFilter: val,
loading: true
});
}
// ...
}
最後,我們讓我們更新的updateData()
功能以考慮搜尋。
class SearchableContent extends React.Component {
// ...
this.setState({loading: true}, this.updateData);
// ...
}
雖然這可能看起來很複雜,它但實際上幾乎與我們現有的updateData()
函式完全相同,除了我們更新fetch()
查詢查詢結果以呼叫filter()
JSON集合上的方法。
所有collection.filter()
函式都執行為每個元素傳入的函式,並過濾掉報道檢視虛假值的值,保留返回真值的值。我們的搜尋功能只是在Github的活動actor.login
(Github的使用者)上查詢匹配,以檢視它是否與該searchFilter
值匹配。
隨著updateData()
功能的更新,我們的搜尋已經完成。
嘗試搜尋auser
。
現在我們有一個3層應用程式元件,用於處理巢狀子元件的搜尋。我們用這篇文章從初學者跳到中級。拍拍自己的背部。這是一些沉重的材料。請確保您理解這一點,因為我們會經常使用我們今天介紹的這些概念。
在下一節中,我們將跳出來看看構建純元件。
學習REACT正確的方法
React和朋友的最新,深入,完整的指南。
下一章:
純元件