前言
本文為react入門介紹,一些基本的概念和知識點,僅供未使用過react童鞋瞭解參考,若已使用過react,則此文對你可能毫無價值。
React 簡介
React的意義
React 把過去不斷重複構建 UI 的過程抽象成了元件,且在給定引數的情況下約 定渲染對應的 UI 介面。React 能充分利用很多函式式方法去減少冗餘程式碼。此外,由於它本身就 是簡單函式,所以易於測試。可以說,函數語言程式設計才是 React 的精髓
JSX(含易錯點)
JSX簡介
下面是最簡單的JSX變數
const element = <h1>Hello, world!</h1>;
複製程式碼
可以在JSX內直接使用JavaScript 表示式,但是:在 JSX 當中的表示式要包含在大括號裡
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
複製程式碼
JSX屬性
引號定義字串屬性,大括號定義以JS表示式為值的屬性。 但是:大括號外面再巢狀引號,會將引號內的都處理為字串
const element = <div tabIndex="0"></div>;
const element = <img src={user.avatarUrl}></img>;
複製程式碼
JSX巢狀
標籤是閉合的,必須像HTML那樣有結尾,如 /> JSX使用駝峰法定義屬性名稱,更像JS
JSX代表objects 物件
元件
元件從概念上看就像是函式,它可以接收任意的輸入值(稱之為“props”),並返回一個需要在頁面上展示的React元素。 props就像是即將傳入元件的引數 下方是定義一個元件的方法,它接收一個單一的props”物件並返回一個React元素。我們之所以稱這種型別的元件為函式定義元件,是因為從字面上來看,它就是一個JavaScript函式。
//使用JS函式
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
//使用ES6 class
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
複製程式碼
元件渲染
當React遇到的元素是使用者自定義的元件,它會將JSX屬性作為單個物件傳遞給該元件,這個物件稱之為“props”。例如,這段程式碼會在頁面上渲染出"Hello,Sara":
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
複製程式碼
元件必須以大寫字母開頭
元件組合
元件可以組合,但是:元件的返回值只能有一個根元素。這也是我們要用一個div包裹元件元素的原因
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
複製程式碼
元件提取(重點)
//原複雜元件,不可重用
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name} />
</div>
</div>
);
}
//拿出來獨立的部分,自定義元件(因為是元件,所以author和user究竟叫什麼,意義不大,只要元件易懂即可)
function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
//當需要使用Avatar這個元件的時候,傳入屬性值,能夠從父元件得到資料即可,這裡假設,父元件的屬性,就是命名為author,現在使用Avatar:
<Avatar user={props.author} />
//可以看到,這裡,Avatar就的user就是它父元件的author,獲得了屬性值。這就是最基本的元件提取
複製程式碼
props的只讀性
像純函式那樣使用props:當它沒有改變它自己的輸入值,當傳入的值相同時,總是會返回相同的結果。state可以在不違反上面規則的前提下,動態改變輸出
state和生命週期
定義為類的元件,才有額外的特性。
將函式轉換為類
方法步驟:
- 建立一個名稱擴充套件為React.Component的ES6 類
- 建立一個叫做render()的空方法
- 將函式體移動到render()方法中
- 在render()方法中,使用this.props替換props
- 刪除剩餘的空函式宣告
//原 函式定義的元件
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
//現 類元件
class Clock extend React.Component{
render(){
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
複製程式碼
還有一種老方法,React.createClass,區別點選連結
事件處理
語法不同
- React事件繫結屬性的命名採用駝峰式寫法,而不是小寫。
- 如果採用 JSX 的語法你需要傳入一個函式作為事件處理函式,而不是一個字串(DOM元素的寫法)
//HTML寫法
<button onclick="activateLasers()">
Activate Lasers
</button>
//JSX寫法
<button onClick={activateLasers}>
Activate Lasers
</button>
複製程式碼
阻止預設行為
不能使用返回 false 的方式阻止預設行為。你必須明確的使用 preventDefault
//HTML
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
//reafunction ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
複製程式碼
2種事件處理的寫法(疑問:為什麼必須將handleClick: function(event)等換成handleClick(event)才能順利執行?)
//第一種,ES6寫法
class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = {liked: true};
this.handleClick = this.handleClick.bind(this);
}
getInitialState() {
return {liked: false};
}
handleClick(event) {
this.setState({liked: !this.state.liked});
}
render() {
var text = this.state.liked ? '喜歡' : '不喜歡';
return (
<p onClick={this.handleClick}>
你<b>{text}</b>我。點我切換狀態。
</p>
);
}
}
ReactDOM.render(
<LikeButton />,
document.getElementById('root')
);
//第二種
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false};
},
handleClick: function(event) {
this.setState({liked: !this.state.liked});
},
render: function() {
var text = this.state.liked ? '喜歡' : '不喜歡';
return (
<p onClick={this.handleClick}>
你<b>{text}</b>我。點我切換狀態。
</p>
);
}
});
ReactDOM.render(
<LikeButton />,
document.getElementById('root')
);
複製程式碼
條件渲染
與JS種使用沒什麼區別,使用較簡單
與運算子 && 的特性
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
複製程式碼
在 JavaScript 中,true && expression 總是返回 expression,而 false && expression 總是返回 false。因此,如果條件是 true,&& 右側的元素就會被渲染,如果是 false,React 會忽略並跳過它。
列表 keys
map()函式
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);//[2, 4, 6, 8, 10]
複製程式碼
使用map()渲染列表
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((numbers) =>
<li>{numbers}</li>
);//listItems 渲染的是很多個<li></li>標籤,裡面的內容是numbers經過map()出來的,所以下方會渲染出5個li,外面需加上ul巢狀,否則報錯?(**需確認**)
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
複製程式碼
用keys提取元件
官方文件的解釋有點不夠清晰 實際上,在哪輸出列表,就是在哪定義key。即使使用某元件接收列表值,也是在接收的時候定義key,而不是在這個元件中定義key。其實這個稍微想一想就可以理解了。 元件就是放在那給大家使用的,誰都能用,你給他定義了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('root')
);
複製程式碼
表單
受控元件
像<input><textarea>, 和 <select>
這類表單元素會維持自身狀態,並根據使用者輸入進行更新。但在React中,可變的狀態通常儲存在元件的狀態屬性中,並且只能用 setState(). 方法進行更新
這邊直接可以在文件中檢視,連結
在react中,<input>,<textarea><select>
是非常相似的,也是用this.state = {value: '你好.'};
設定預設值。用handleChange(event) {this.setState({value: event.target.value});}
獲取輸入值,用<textarea value={this.state.value} onChange={this.handleChange} />
動態渲染輸入值。
但是在React中,會在根select標籤上而不是在當前的selected屬性上使用value屬性。程式碼連結
//通過以下程式碼可以看到,{value: 'lime'}中的預設值是小寫的,即,是標籤上的屬性,否則預設選擇第一個屬性
this.state = {value: 'lime'};
//省略程式碼
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
複製程式碼
多個輸入框的解決辦法
當你有處理多個受控的input元素時,你可以通過給每個元素新增一個name屬性,來讓處理函式根據 event.target.name的值來選擇做什麼。
class Reservation extends React.Component {
constructor(props) {
super(props);
//this.state這邊設定預設值
this.state = {
isGoing: true,
numberOfGuests: 2
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
//定義目標的name值
const name = target.name;
//this.setState這邊根據標籤的name,來確定設定的值
this.setState({
[name]: value
});
}
render() {
return (
<form>
<label>
Is going:
<input
//這裡的name
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Number of guests:
<input
//這裡的name
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
</form>
);
}
}
複製程式碼
狀態提升
點選連結參考詳細文件
組合繼承
首先**children
是保留關鍵字**,在使用props.children的時候,才能在元件中直接巢狀JSX
只有當此處是children時,才能在元件中直接巢狀JSX。自定義的元件應當屬性傳遞給父元件
function Child() {
return <div>子元件</div>;
}
function Father(props) {
return (
<div>
<p>父元件</p>
{props.aaa}
</div>
);
}
function App() {
return (
<Father aaa={<Child/>}>
<p>直接巢狀的JSX</p>
</Father>
);
}
ReactDOM.render(
<App/>,
document.getElementById('root')
);
//上面的程式碼顯示為:父元件 子元件
function Child() {
return <div>子元件</div>;
}
function Father(props) {
return (
<div>
<p>父元件</p>
{props.children}
</div>
);
}
function App() {
return (
<Father children={<Child/>}>
<p>直接巢狀的JSX</p>
</Father>
);
}
ReactDOM.render(
<App/>,
document.getElementById('root')
);
//上面的程式碼顯示為: 父元件 直接巢狀的JSX
複製程式碼