- 標簽里用到
<label for>
的,for
要寫成htmlFor
- 標簽里的
class
要寫成className
- 組件首字母一定要大寫
- 單標簽最后一定要閉合
- 如果html里要空格轉義,
注意不要漏了分號; - style要寫成
style={{clear: 'both',backgroundColor:'red',width:'200px'}}
- 組件里能用
<button>
的地方就不要用input type="button"
了,否則寫個value
還要用{}
- 標簽里的
ref
屬性的屬性名不要出現中橫杠比如message-content
,如果有多個單詞,直接寫成駝峰形式 - 把要改變的數據寫進父組件的
getInitialState
的屬性里,然后通過this.props.listArr
傳進去,表明初始狀態是組件里listArr
里的屬性。 - 如果將子組件改變的數據傳遞給父組件呢?可以在父組件里申明一個函數,里面傳參
data
,然后在創建出子組件的對象的時候在屬性上傳入父組件的這個函數,然后在子組件里觸發了某個事件的函數里,通過this.props.addItem()
這樣的方式調用父組件的函數,這個addItem
就是父組件的函數,里面傳參 - 如果組件之間的通信超過的一層,傳參就非常麻煩,需要用到
react
的一個插件叫PubSub
訂閱發布
(1) 先導入庫
(2) 全局設置一個事件名稱,子組件和父組件共用,比如var deleteItem = 'deleteItem';
(3) 子組件,觸發事件之后,發布事件
//使用PubSub.publish(),第一個參數是公用的事件名稱,第二個參數是你要傳播的值
deleteItemHandler:function(){
PubSub.publish(deleteItem, this.props.item);
},
(4) 父組件,是等組件全部渲染之后,因為組件還在內存中,虛擬DOM還沒有渲染出來,沒有正式出現在頁面上時,是獲取不到真是DOM的,所以在componentDidMount
的函數里訂閱一個從子組件發布出來的事件,在渲染完成后,會自動觸發這個函數
//使用PubSub.subscribe(),第一個參數是公用的事件名稱,第二個參數是一個回調函數,可以是用箭頭函數方式使它內部this指向組件對象,evName是事件對象,data就是子組件發布過來,這里接受到的data
componentDidMount:function(){
PubSub.subscribe(deleteItem,(evName,data) =>{
var newArr = this.state.listArr.filter(function(item,index){
return item!= data;
});
this.setState({
listArr:newArr
});
});
},
- 這里順便復習一下
Array
的filter()
方法,參數里是個函數,參數是項和下標,return
里寫一個條件,所有符合條件的都會提取出來放到一個新的數組里,這里將數組里不等於傳回來的這個data
里的值的每一項都放到了newArr
里,然后通過setState()
,更新state
里數組的值 - 利用
ReactCSSTransitionGroup
來添加一些簡單的動畫效果,比如列表內容增加或者刪除時可以有漸進漸出的效果。但是這個標簽默認是span
標簽,使用在table
或者options
里提示警告,不能在table
和options
里嵌套span
,所以可以通過它本身的component
屬性,比如component="div"
直接將這個標簽渲染為我們需要的標簽即可。另外css
里對應的動畫時間要和這里標簽里的時間對應
var ListComponent = React.createClass({
render: function(){
return (
<ReactCSSTransitionGroup component="div" id="message-container" transitionName="messageContainer" transitionEnterTimeout={800} //這里定義漸進的時間
>
{ //這里放該組件的子級,也就意味寫着這里面所有的內容的都會有動畫效果,
this.props.mesArr.map(function(ele){
return <ItemComponent key={ele.time} {...ele} />
})
}
</ReactCSSTransitionGroup>
)
}
});
- 通過搜索框輸入字符讓顯示區即時地篩選出搜索結果的效果。這里的難點是,如果直接通過
onChange
來獲取打入的字符串來更新父組件的state
里的數據,會造成數據返回不到原來的狀態。所以思路可以是這樣的,在父組件state
里先創建一個空數組,每次當搜索框獲取到焦點時,就把父組件當前的顯示數據賦值給這個新建的數組,然后filter
的時候是通過這個新數組里的數據進行篩選,而不是原來的數據,另外,當搜索框內容為空或者失去焦點時,再把視圖的數據恢復到得到焦點時的狀態即可。下面是可以實現的父組件中的代碼:
//在搜索框聚焦時,將當前state里的userList賦值給currentList,然后每次輸入,篩選的對象都是currentList
focusHandler:function(){
this.state.currentList = this.state.userList;
},
//在失去焦點時立刻將剛才存儲的currentList賦值給userList,讓視圖再恢復到點擊搜索框之前
blurHandler:function(){
this.setState(function(){
return {
userList: this.state.currentList
}
});
},
//搜索功能
searchUser:function(text){
//這里要將text進行判斷,如果為空,就要讓視圖呈現剛聚焦時的狀態,否則就進行篩選
if(text!=''){
var newText = text.toLowerCase();
var newArr = this.state.currentList.filter(function(item){ //每次點擊通過保存的currentList來過濾
return item.username.toLowerCase().indexOf(newText) != -1;
});
this.setState(function(){
return {
userList: newArr
}
});
}else{
this.setState(function(){
return {
userList: this.state.currentList
}
});
}
},
- React-Router和動畫的結合使用
除了兩種技術的結合之外,有個很重要的地方不要忘記,就是要讓每個單獨的組件設置樣式為position:absolute,否則在動畫切換時會出現短暫組件疊加的的情況,用戶體驗非常差,但是絕對定位后,每個組件都在同一個地方漸入漸出了。
//這里是react創建組件的ES6新寫法,省略了function和內部的render,return。
const MenuComponent = ({ children, location }) => (
<div> //這里是將組件Menu下控制的路由寫在這里,每個路徑用Link標簽包起來,通過屬性to來控制對應不同的路徑
<div className="col-md-3 list-group">
<Link to="/statistic" className="list-group-item active">Website Statistic
Data</Link>
<Link to="/topics" className="list-group-item">Hot Topics</Link>
<Link to="/visits" className="list-group-item">Today's Visits</Link>
<Link to="/status" className="list-group-item">Server Status</Link>
</div>
//這里把要對應的做成動畫的區域用ReactCSSTransitionGroup包起來
<ReactCSSTransitionGroup className="col-md-9 pr clearfix"
component="div"
transitionName="content"
transitionEnterTimeout={500}
transitionLeaveTimeout={500}
>
{React.cloneElement(children, {key: location.pathname,className:"pa"})}
</ReactCSSTransitionGroup>
</div>
)
--------------------------------------------------------------
//這里是render方法里的寫法
ReactDOM.render(
<Router> //根路由
// "/"代表根路由,IndexRoute表示索引頁,如果沒有索引頁可以作為默認顯示的內容
<Route path="/" component={MenuComponent}>
<IndexRoute component={StatisticComponent} />
<Route default path="statistic" component={StatisticComponent} />
<Route path="topics" component={TopicComponent} />
<Route path="visits" component={GuestComponent} />
<Route path="status" component={StateComponent} />
</Route>
</Router>
,document.getElementById('container')
);
- 用ES6的箭頭函數寫組件
const MenuComponent = ({ children, location }) => {
//定義組件里的函數直接在組件里申明即可
const changeLink = (ev) => {
var parent = ev.target.parentNode;
var children = parent.children;
for(var i=0; i<children.length; i++){
children[i].classList.remove('active');
}
ev.target.classList.add('active');
};
//這屆寫return (),里面寫標簽
return (
<div>
<div className="col-md-3 list-group" onClick={changeLink}> //這里不用再寫this.changeLink了
<Link to="/statistic" className="list-group-item active">Website Statistic
Data
</Link>
<Link to="/topics" className="list-group-item">Hot Topics</Link>
<Link to="/visits" className="list-group-item">Today's Visits</Link>
<Link to="/status" className="list-group-item">Server Status</Link>
</div>
<ReactCSSTransitionGroup className="col-md-9 pr"
component="div" transitionName="content" transitionEnterTimeout={500} transitionLeaveTimeout={500}
>
{React.cloneElement(children, {key: location.pathname, className: "pa"})}
</ReactCSSTransitionGroup>
</div>
);
};