react學習總結2--基礎(二)
react 學習總結–基礎(二)
說明
React 版本 :”15.4.1”
react-tap-event-plugin 版本: “^2.0.1”
1.資料流
在 React 中,資料流的流向是單向的–從父節點傳遞到子節點,因而元件是簡單且易於把握的,他們只需從父節點獲取props渲染即可
React 元件內部還具有自己的狀態,這些狀態只能在元件內修改,React元件本身很簡單,可以把它看成是一個函式,他接受 props 和 state 作為引數,返回一個虛擬DOM表現
Props(屬性)
props 就是 properties 的縮寫,你可以使用它把任意型別的資料傳遞給元件。可以在掛在元件的時候設定它的props
let obj = {name : 'aaa', age : 20 };
<Child obj={obj} />
通過元件例項的setProps方法(很少這樣做)來設定props
let obj = {name : 'aaa', age : 20};
let myChild = ReactDOM.render(
<Child />,
document.getElementById('app')
);
myChild.setProps({name : 'bbb'});
注:在元件內,props只能由父元件傳遞進來,子元件內不能修改自己的 props ,即不能通過this.setProps,或者this.props直接修改props
props的格式,可以設定為字串,
<a href="/home"></a>
也可以使用{},注入JavaScript傳遞任意型別的變數<a href={'/home/' + this.state.id}></a>
,新增事件處理<a onClick={this.handleClick}></a>
也可以使用展開語法<Child {...props} />
State(狀態)
React 將元件看成一個狀態機,有一個初始狀態,然後隨著與使用者的互動,導致狀態變化,從而觸發重新渲染UI 每一個React元件都可以擁有自己的state,元件的state只存在於元件內部
state可以通過setState來修改,也可以通過getInitialState方法提供一組預設值,只要setState被呼叫,render方法就會被呼叫,如果render返回值有變化,虛擬DOM就會更新
注:不能使用
this.state.name = 'name'
這樣的方式修改state,只能通過this.setState({name : 'name'})
這種方式修改
class Test extends Component {
constructor(props) {
super(props);
this.state = {
num : 0
};
}
componentDidMount() {
this.setState({num : 2});
}
render() {
return (
<Child childNum={this.state.num} />
);
}
}
PropTypes(props驗證)
元件的屬性可以是任意值,但有時候我們需要驗證別人使用元件的時候,提供的引數是否符合要求,PropsTypes屬性,就是React提供的驗證傳入props的有效性的方式
當向props傳入無效資料時,JavaScript控制檯會丟擲警告為了效能考慮,只在開發環境驗證propsTypes
class Modal extends Component {
static propTypes = {
children: PropTypes.node, //表示這些 props 是可傳可不傳的
isOpen: PropTypes.bool.isRequired, //表示這些 props 不可以為空
}
...
}
這裡有更詳細的驗證器
2.事件處理
React 事件處理本質上跟JavaScript事件一樣,命名上與JavaScript一致,並且會在相同的情景下觸發,React標準化了事件物件,使用駝峰式命名
<input type="button" onClick={this.handleClick.bind(this)}>
,顯式的呼叫bind(this)
,將函式上下文繫結到元件例項上。
事件捕獲處理
一般寫法
onClick={this.handleClick.bind(this)}
會在事件冒泡階段觸發,如果想在事件捕獲階段觸發需要加上Capture
,例如onClickCapture={this.handleCaptureClick.bind(this)}
虛擬事件物件
React 的事件物件event是經過封裝的,沒有瀏覽器相容問題,他有和瀏覽器本地事件相同的屬性和方法
但是如果需要呼叫底層的瀏覽器事件物件,只需要使用nativeEvent
屬性就可以獲取,
常用的屬性和方法如下
stopPropagation()
阻止事件冒泡preventDefault()
阻止預設事件target
觸發事件的物件currentTarget
繫結事件的物件nativeEvent
原生瀏覽器事件物件type
事件型別
觸控事件
舊版本的 React 為了使觸控事件生效,需要在渲染所有元件之前呼叫
React.initializeTouchEvents(true)
,
但是在新版本的 React 中已經停用,要使用觸控事件需要引入react-tap-event-plugin
,然後在渲染所有元件之前,呼叫injectTapEventPlugin();
為避免300ms之後再次觸發onClick(也就是點選一次,反應兩次)可以進行配置
injectTapEventPlugin({
shouldRejectClick: function (lastTouchEventTimestamp, clickEventTimestamp) {
return true;
}
});
3.複合元件
本質上,一個元件就是一個JavaScript函式,它接受props和state兩個引數,並輸出渲染好的HTML,元件一般被用於呈現和表達應用的某部分資料
我們可以通過建立多個元件來合成一個元件,即把元件的不同功能點進行分離
class ChildBtn extends Component{
constructor(props) {
super(props);
}
render() {
return <button>點選</button>;
}
}
class ChildInput extends Component{
constructor(props) {
super(props);
}
render() {
return <input type="text" />;
}
}
class Test extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<ChildInput />
<ChildBtn />
</div>
);
}
}
子級
<Parent><Child /></Parent>
如上,Child 就是 Parent 的子級,在Parent中能通過
this.props.children
讀取子級
4.Mixin
mixin允許我們定義可以再多個元件中共用的方法,它們就是混合近元件中的物件而已,React的Mixin
能夠防止靜默函式覆蓋,同時支援多個Mixin混合
React.createClass({
mixins : [{
getInitialState: function(){return {a : 1}}
}],
getInitialState: function(){return {b : 2}}
});
//最終結果:state => {a:1,b:2}
ES6 寫法
如果要使用ES6編寫React元件,不建議使用Mixins機制,將會使用高階元件代替代Mixins,更多詳情請看
高階元件替代Mixins
5.DOM操作
多數情況下,React的虛擬DOM足以用來建立你想要的使用者體驗,但是有些情況下不得不操作底層的DOM,例如:使用第三方類庫,或者執行一個React沒有原生支援的操作,為了是這些操作變得容易,React提供了一個可以用於處理受其自身控制的DOM節點的方法,這些方法在元件生命週期的特定階段才能被訪問到
ref屬性
ref屬性,用來配合獲取真實的DOM節點,下邊是一個例子
class Test extends Component {
constructor(props) {
super(props);
this.state = {
value : ''
}
}
handleClick(){
let textInput = ReactDOM.findDOMNode(this.refs.text);
console.log(textInput); // 獲取到真實DOM元素
}
handleChange(e){
this.setState({value : e.target.value});
}
render() {
return (
<div>
<input type="text"
ref="text"
value={this.state.value}
onChange={this.handleChange.bind(this)}
/>
<button onClick={this.handleClick.bind(this)}>獲取輸入內容</button>
</div>
);
}
}
訪問到相應的DOM節點,需要通過
this.refs.[refName]
找到相應的子元件,定義ref,必須保障賦給每個子元件的ref值在所有的子元件中是唯一的,找到子元件後,通過ReactDOM.findDOMNode()
方法訪問到底層的DOM節點注意:只有在元件被掛載後才能訪問,在有些生命週期中可以訪問到,但獲取的DOM不是最新的,以下是其執行環境
- componentDidMount
- componentDidUpdate
- 事件處理函式中(事件處理函式都是在元件掛載後觸發)
注:舊版本會用
this.refs.text.getDOMNode()
的方式獲取,新版本中已經不能使用,替換為ReactDOM.findDOMNode(this.refs.text)
注:有其他方式能夠實現功能時,儘量不要使用此功能,在效能上會有一定障礙,同時增加了元件的複雜性
6.表單
表單元件不同於其他元件,因為他們可以通過使用者交互發生變化
表單元件支援幾個受使用者互動影響的屬性
- value,用於
<input>
、<textarea>
元件。 - checked,用於型別為
checkbox
或者radio
的<input>
元件。 - selected,用於
<option>
元件。
無約束元件
即表單元件的值是不受React控制的,在React中,這種行為與設定
<input />
的 defaultValue一致
我們可以通過設定defaultValue屬性設定預設值
class MyForm extends Component{
render() {
return (
<input type="text" defaultValue="hello" />
);
}
}
這個例子展示的就是無約束元件,元件的value並非由父元件設定,而是讓
<input />
自己控制自己的值
約束元件
也就是表單元件的狀態交由React元件控制,狀態值被儲存到React元件的state中
class MyForm extends Component{
constructor(props){
super(props);
this.state = {
value
};
}
handleChange(e){
this.setState({value : e.target.value})
}
render() {
return (
<input type="text"
value={this.state.value}
onChange={this.handleChange.bind(this)}
/>
);
}
}
<input />
的值儲存在父元件的state中
文字框和select
React 對
<textarea />
和<select/>
做了一些修改,提升了一致性
<textarea name="description" value="This is a description." />
<select value={this.state.value} onChange={this.handleChange.bind(this)}>
<option value="A">fir</option>
<option value="B">sec</option>
<option value="C">thr</option>
</select>
單選框和複選框
class Test extends Component{
constructor(props){
super(props);
this.state = {
checked : false
};
}
handleChange(e){
this.setState({checked : e.target.checked})
}
render() {
return (
<input type="checkbox"
checked={this.state.checked}
onChange={this.handleChange.bind(this)}
/>
);
}
}
7.會用到的API
ReactDOM.unmountComponentAtNode
ReactDOM.unmountComponentAtNode(DOMElement containe)
銷燬指定容器內的所有React節點。
ReactDOM.unmountComponentAtNode(document.getElementById('app'));
注:只能銷燬
ReactDOM.render(<app />,document.getElementById('app'))
中的容器內部節點,通過react產生的節點使用此方法回報錯:
ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(this.refs.remove));
warning.js:36 Warning: unmountComponentAtNode(): The node you're attempting to unmount was rendered by React and is not a top-level container. Instead, have the parent component update its state and rerender in order to remove this component.
React.isValidElement
React.isValidElement(object)
判斷一個物件是否是一個ReactElement(不是很常用)
let c = <Test />;
console.log(React.isValidElement(c));//true
只有在判斷的物件是例項化的react元件時,才會返回true
React.cloneElement()
React.cloneElement()
克隆並返回一個新的 ReactElement (內部子元素也會跟著克隆),新返回的元素會保留有舊元素的 props、ref、key。可以傳入三個引數
1.要克隆的ReactElement;2.需要新新增的屬性props;3.重新設定的子節點(會替換掉原本的子節點)
render() {
let span = <span ref="span">aaa</span>;
let spanChange = React.cloneElement(span, {name:'aaa'} ,<em>bbb</em>);
return (
<div>
{spanChange}
</div>
);
}
//結果:<span name="aaa"><em>bbb</em><span>
React 遍歷
React.Children.map()
可以實現遍歷,但是我一般直接用map
render() {
let arr = ['A','B','C','D'];
return (
<div>
<ul>
{
arr.map((item,i) => {
return (<li key={i}>{item}</li>)
})
}
</ul>
</div>
);
}
注意:像這樣迴圈新增react節點的操作一定要加上key屬性,否則會有警告:
warning.js:36Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of
Test. See https://fb.me/react-warning-keys for more information.
forceUpdate
forceUpdate()
就是重新執行render,有些變數不在state上,但是又想達到變數更新,重新render的效果的時候,就可以使用此方法手動觸發render
handleClick(){
this.forceUpdate(function () {
console.log('update'); //render之後的回撥
});
}
一些使用es6就不能使用的API
- replaceState
- isMounted
- Mixin
下一篇–React-Router傳送門
- API,及常用方法