react基礎篇四
列表 & Keys
渲染多個組件
你可以通過使用{}
在JSX內構建一個元素集合
下面,我們使用Javascript中的map()
方法遍歷numbers
數組。對數組中的每個元素返回<li>
標簽,最後我們得到一個數組listItems
我們把整個listItems
插入到ul
元素中,然後渲染進DOM:
ReactDOM.render( <ul>{listItems}</ul>, document.getElementById(‘root‘) );
function NumberList(props) { const numbers= props.numbers; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> ); return ( <ul>{listItems}</ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById(‘root‘) );
一個元素的key最好是這個元素在列表中擁有的一個獨一無二的字符串。通常,我們使用來自數據的id作為元素的key
如果列表項目的順序可能會變化,我們不建議使用索引來用作鍵值,因為這樣做會導致性能的負面影響,還可能引起組件狀態問題。如果你想要了解更多,請點擊深度解析key的必要性。如果你選擇不指定顯式的鍵值,那麽React將默認使用索引用作為列表項目的鍵值。
鍵(key)只是在兄弟之間必須唯一
數組元素中使用的key在其兄弟之間應該是獨一無二的。然而,它們不需要是全局唯一的。當我們生成兩個不同的數組時,我們可以使用相同的鍵
function Blog(props) { const sidebar= ( <ul> {props.posts.map((post) => <li key={post.id}> {post.title} </li> )} </ul> ); const content = props.posts.map((post) => <div key={post.id}> <h3>{post.title}</h3> <p>{post.content}</p> </div> ); return ( <div> {sidebar} <hr /> {content} </div> ); } const posts = [ {id: 1, title: ‘Hello World‘, content: ‘Welcome to learning React!‘}, {id: 2, title: ‘Installation‘, content: ‘You can install React from npm.‘} ]; ReactDOM.render( <Blog posts={posts} />, document.getElementById(‘root‘) );
key會作為給React的提示,但不會傳遞給你的組件。如果您的組件中需要使用和key
相同的值,請用其他屬性名顯式傳遞這個值:
const content = posts.map((post) => <Post key={post.id} id={post.id} title={post.title} /> );
上面例子中,Post
組件可以讀出props.id
,但是不能讀出props.key
表單
HTML表單元素與React中的其他DOM元素有所不同,因為表單元素生來就保留一些內部狀態。例如,下面這個表單只接受一個唯一的name。
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
當用戶提交表單時,HTML的默認行為會使這個表單跳轉到一個新頁面。在React中亦是如此。但大多數情況下,我們都會構造一個處理提交表單並可訪問用戶輸入表單數據的函數。實現這一點的標準方法是使用一種稱為“受控組件”的技術。
受控組件
在HTML當中,像<input>
,<textarea>
, 和 <select>
這類表單元素會維持自身狀態,並根據用戶輸入進行更新。但在React中,可變的狀態通常保存在組件的狀態屬性中,並且只能用 setState()
方法進行更新。
我們通過使react變成一種單一數據源的狀態來結合二者。React負責渲染表單的組件仍然控制用戶後續輸入時所發生的變化。相應的,其值由React控制的輸入表單元素稱為“受控組件”。
例如,我們想要使上個例子中在提交表單時輸出name,我們可以寫成“受控組件”的形式:
class NameForm extends React.Component { constructor(props) { super(props); this.state = {value: ‘‘}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } handleSubmit(event) { alert(‘A name was submitted: ‘ + this.state.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input type="text" value={this.state.value} onChange={this.handleChange} /> </label> <input type="submit" value="Submit" /> </form> ); } }
在 CodePen 上嘗試。
由於 value
屬性是在我們的表單元素上設置的,因此顯示的值將始終為 React數據源上this.state.value
的值。由於每次按鍵都會觸發 handleChange
來更新當前React的state,所展示的值也會隨著不同用戶的輸入而更新。
使用”受控組件”,每個狀態的改變都有一個與之相關的處理函數。這樣就可以直接修改或驗證用戶輸入。例如,我們如果想限制輸入全部是大寫字母,我們可以將handleChange
寫為如下:
handleChange(event) { this.setState({value: event.target.value.toUpperCase()});
在React應用中,對應任何可變數據理應只有一個單一“數據源”。通常,狀態都是首先添加在需要渲染數據的組件中。然後,如果另一個組件也需要這些數據,你可以將數據提升至離它們最近的共同祖先中。你應該依賴 自上而下的數據流,而不是嘗試在不同組件中同步狀態。
組合 vs 繼承(即slot)
包含關系
一些組件不能提前知道它們的子組件是什麽。這對於 Sidebar
或 Dialog
這類通用容器尤其常見。
我們建議這些組件使用 children
屬性將子元素直接傳遞到輸出。
function FancyBorder(props) { return ( <div className={‘FancyBorder FancyBorder-‘ + props.color}> {props.children} </div> ); }
這樣做還允許其他組件通過嵌套 JSX 來傳遞子組件。
function WelcomeDialog() { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> Welcome </h1> <p className="Dialog-message"> Thank you for visiting our spacecraft! </p> </FancyBorder> ); }
雖然不太常見,但有時你可能需要在組件中有多個入口,這種情況下你可以使用自己約定的屬性而不是 children
:
function SplitPane(props) { return ( <div className="SplitPane"> <div className="SplitPane-left"> {props.left} </div> <div className="SplitPane-right"> {props.right} </div> </div> ); }
function App() { return ( <SplitPane left={ <Contacts /> } right={ <Chat /> } /> ); }
在 CodePen 上試試。
類似 <Contacts />
和 <Chat />
這樣的 React 元素都是對象,所以你可以像任何其他元素一樣傳遞它們。
react基礎篇四