剛開始不久react,在菜鳥上及其他前輩網站上學習,下面開始我的自學筆記。
包括:
- 渲染元素
- 組件(函數方法定義、es6 class定義)
- 事件處理
- 條件渲染
- 列表
下面代碼部分將不會再寫html部分,html部分如下:
<div id="example"></div>
多余的話不多說,具體如下:
- 渲染元素(函數方法,es6方式)
- 函數方法
function Clock(props) { return ( <div> <h1>Hello, world!</h1> <h2>現在是 {props.date.toLocaleTimeString()}.</h2> </div> ); } function tick() { ReactDOM.render( <Clock date={new Date()} />, document.getElementById('example') ); } setInterval(tick, 1000);
-
- es6方法
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>現在是 {this.props.date.toLocaleTimeString()}.</h2> </div> ); } } function tick() { ReactDOM.render( <Clock date={new Date()} />, document.getElementById('example') ); } setInterval(tick, 1000);
- 組件
1、我們可以使用函數定義一個組件:
function HelloMessage(props) { return <h1>Hello World!</h1>; }
也可以使用ES6 class來定義一個組件:
class Welcome extends React.Component { render() { return <h1>Hello World!</h1>; } }
2.需要向組件傳遞參數,可以使用this.props對象
function HelloMessage(props) { return <h1>Hello {props.name}!</h1>; } const element = <HelloMessage name="Runoob"/>; ReactDOM.render( element, document.getElementById('example') );
注意:在添加屬性時,class屬性需要寫成className,for屬性需要寫成htmlFor,這是因為class和for是JavaScript的保留字。
復合組件
可以通過創建多個組件來合成一個組件,即把組件的不同功能點進行分離。
<script type="text/babel"> function Name(props) { return <h1>名稱:{props.name}</h1>; } function Url(props) { return <h1>地址:{props.url}</h1>; } function Nickname(props) { return <h1>小名:{props.nickname}</h1>; } function App() { return ( <div> <Name name="Tom" /> <Url url="https://www.cnblogs.com/freedom-feng/" /> <Nickname nickname="Jack" /> </div> ); } ReactDOM.render( <App />, document.getElementById('example') ); </script>
- 事件
使用 ES6 class 語法來定義一個組件的時候,事件處理器會成為類的一個方法(推薦方式)。例如,下面的 Toggle 組件渲染一個讓用戶切換開關狀態的按鈕:
class Toggle extends React.Component { constructor(props) { super(props); this.state = {isToggleOn: true}; // 這邊綁定是必要的,這樣 `this` 才能在回調函數中使用 this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); } render() { return ( <button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> ); } } ReactDOM.render( <Toggle />, document.getElementById('example') );
注意:類的方法默認是不會綁定 this 的。如果你忘記綁定 this.handleClick 並把它傳入 onClick, 當你調用這個函數的時候 this 的值會是 undefined。
如果上面使用 bind 讓你很煩,這里有兩種方式可以解決。如果你正在使用實驗性的屬性初始化器語法,你可以使用屬性初始化器來正確的綁定回調函數:
<script type="text/babel"> class LoggingButton extends React.Component { // 這個語法確保了 `this` 綁定在 handleClick 中 // 這里只是一個測試 handleClick = () => { console.log('this is:', this); } render() { return ( <button onClick={this.handleClick}> Click me </button> ); } } ReactDOM.render( <LoggingButton />, document.getElementById('example') ); </script>
如果你沒有使用屬性初始化器語法,你可以在回調函數中使用 箭頭函數:
class LoggingButton extends React.Component { handleClick() { console.log('this is:', this); } render() { // 這個語法確保了 `this` 綁定在 handleClick 中 return ( <button onClick={(e) => this.handleClick(e)}> Click me </button> ); } }
-
- 事件傳參
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
上面兩種方式是等價的。
在例子中,參數e作為時間對象將被作為第二個參數進行傳遞。通過箭頭函數的方式,事件對象必須顯式的進行傳遞,但是通過bind的方式,時間對象以及更多的參數將會被隱式的進行傳遞。
注意:通過bind方式向監聽函數傳參,在類組件中定義的監聽函數,事件對象e要排在所傳參數的后面,例如:
<script type="text/babel"> class Popper extends React.Component{ constructor(){ super(); this.state = {name:'Hello world!'}; } preventPop(name, e){ //事件對象e要放在最后 e.preventDefault(); alert(name); } render(){ return ( <div> <p>hello</p> {/* 通過 bind() 方法傳遞參數。 */} <button onClick={this.preventPop.bind(this,this.state.name)}>Click</button> </div> ); } } ReactDOM.render( <Popper />, document.getElementById('example') ); </script>
- 條件渲染
先看兩個組件:
function UserGreeting(props) { return <h1>歡迎回來!</h1>; } function GuestGreeting(props) { return <h1>請先注冊。</h1>; }
創建一個 Greeting 組件,它會根據用戶是否登錄來顯示其中之一:
function Greeting(props) { const isLoggedIn = props.isLoggedIn; if (isLoggedIn) { return <UserGreeting />; } return <GuestGreeting />; } ReactDOM.render( // 嘗試修改 isLoggedIn={true}: <Greeting isLoggedIn={false} />, document.getElementById('example') );
元素變量
可以使用變量來儲存元素。它可以幫助你有條件的渲染組件的一部分,而輸出的其他部分不會更改。
在下面的例子中,我們將要創建一個名為 LoginControl 的有狀態的組件。
它會根據當前的狀態來渲染 <LoginButton /> 或 <LogoutButton />,它也將渲染前面例子中的 <Greeting />。
class LoginControl extends React.Component { constructor(props) { super(props); this.handleLoginClick = this.handleLoginClick.bind(this); this.handleLogoutClick = this.handleLogoutClick.bind(this); this.state = {isLoggedIn: false}; } handleLoginClick() { this.setState({isLoggedIn: true}); } handleLogoutClick() { this.setState({isLoggedIn: false}); } render() { const isLoggedIn = this.state.isLoggedIn; let button = null; if (isLoggedIn) { button = <LogoutButton onClick={this.handleLogoutClick} />; } else { button = <LoginButton onClick={this.handleLoginClick} />; } return ( <div> <Greeting isLoggedIn={isLoggedIn} /> {button} </div> ); } } ReactDOM.render( <LoginControl />, document.getElementById('example') );
與運算符 &&
用花括號包裹代碼在 JSX 中嵌入任何表達式 ,也包括 JavaScript 的邏輯與 &&,它可以方便地條件渲染一個元素。
<script type="text/babel"> function Mailbox(props) { const unreadMessages = props.unreadMessages; return ( <div> <h1>Hello!</h1> {unreadMessages.length > 0 && <h2> 您有 {unreadMessages.length} 條未讀信息。 </h2> } </div> ); } const messages = ['React', 'Re: React', 'Re:Re: React']; ReactDOM.render( <Mailbox unreadMessages={messages} />, document.getElementById('example') ); </script>
在 JavaScript 中,true && expression 總是返回 expression,而 false && expression 總是返回 false。
因此,如果條件是 true,&& 右側的元素就會被渲染,如果是 false,React 會忽略並跳過它。
三目運算符
條件渲染的另一種方法是使用 JavaScript 的條件運算符:
render() { const isLoggedIn = this.state.isLoggedIn; return ( <div> {isLoggedIn ? ( <LogoutButton onClick={this.handleLogoutClick} /> ) : ( <LoginButton onClick={this.handleLoginClick} /> )} </div> ); }
阻止組件渲染
在極少數情況下,你可能希望隱藏組件,即使它被其他組件渲染。讓 render 方法返回 null 而不是它的渲染結果即可實現。
在下面的例子中,<WarningBanner /> 根據屬性 warn 的值條件渲染。如果 warn 的值是 false,則組件不會渲染:
function WarningBanner(props) { if (!props.warn) { return null; } return ( <div className="warning"> 警告! </div> ); } class Page extends React.Component { constructor(props) { super(props); this.state = {showWarning: true} this.handleToggleClick = this.handleToggleClick.bind(this); } handleToggleClick() { this.setState(prevState => ({ showWarning: !prevState.showWarning })); } render() { return ( <div> <WarningBanner warn={this.state.showWarning} /> <button onClick={this.handleToggleClick}> {this.state.showWarning ? '隱藏' : '顯示'} </button> </div> ); } } ReactDOM.render( <Page />, document.getElementById('example') );
組件的 render 方法返回 null 並不會影響該組件生命周期方法的回調。例如,componentWillUpdate 和 componentDidUpdate 依然可以被調用。
- 列表
使用JavaScript的map()方法來創建列表
const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((numbers) => <li>{numbers}</li> ); ReactDOM.render( <ul>{listItems}</ul>, document.getElementById('example') );
可以將以上實例重構成一個組件,組件接收數組參數,每個列表元素分配一個 key,不然會出現警告 a key should be provided for list items,意思就是需要包含 key:
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('example') );
keys
Keys 可以在 DOM 中的某些元素被增加或刪除的時候幫助 React 識別哪些元素發生了變化。因此你應當給數組中的每一個元素賦予一個確定的標識。
const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> );
一個元素的 key 最好是這個元素在列表中擁有的一個獨一無二的字符串。通常,我們使用來自數據的 id 作為元素的 key:
const todoItems = todos.map((todo) => <li key={todo.id}> {todo.text} </li> );
當元素沒有確定的 id 時,你可以使用他的序列號索引 index 作為 key:
const todoItems = todos.map((todo, index) => // 只有在沒有確定的 id 時使用 <li key={index}> {todo.text} </li> );
如果列表可以重新排序,不建議使用索引來進行排序,因為這會導致渲染變得很慢。
用key提取組件
元素的 key 只有在它和它的兄弟節點對比時才有意義。
錯誤示范:
function ListItem(props) { const value = props.value; return ( // 錯啦!你不需要在這里指定key: <li key={value.toString()}> {value} </li> ); } function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => //錯啦!元素的key應該在這里指定: <ListItem value={number} /> ); return ( <ul> {listItems} </ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('example') );
key正確使用方式:
function ListItem(props) { // 對啦!這里不需要指定key: return <li>{props.value}</li>; } function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => // 又對啦!key應該在數組的上下文中被指定 <ListItem key={number.toString()} value={number} /> ); return ( <ul> {listItems} </ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('example') );
在 map() 方法的內部調用元素時,最好隨時記得為每一個元素加上一個獨一無二的 key。
元素的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('example') );
key 會作為給 React 的提示,但不會傳遞給你的組件。如果您的組件中需要使用和 key 相同的值,請將其作為屬性傳遞:
const content = posts.map((post) => <Post key={post.id} id={post.id} title={post.title} /> );
上面例子中,Post 組件可以讀出 props.id,但是不能讀出 props.key。
在jsx中嵌入map()
在上面的例子中,我們聲明了一個單獨的 listItems 變量並將其包含在 JSX 中:
function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => <ListItem key={number.toString()} value={number} /> ); return ( <ul> {listItems} </ul> ); }
JSX 允許在大括號中嵌入任何表達式,所以我們可以在 map() 中這樣使用:
function NumberList(props) { const numbers = props.numbers; return ( <ul> {numbers.map((number) => <ListItem key={number.toString()} value={number} /> )} </ul> ); }
這么做有時可以使你的代碼更清晰,但有時這種風格也會被濫用。就像在 JavaScript 中一樣,何時需要為了可讀性提取出一個變量,這完全取決於你。但請記住,如果一個 map() 嵌套了太多層級,那你就可以提取出組件。