本文主要是使用ReactJs和Redux來實現一個聊天功能的頁面,頁面極其簡單。使用React時間不長,仍是個noob,有不對之處歡迎你們吐槽指正。html
還要指出這裏沒有使用到websocket等技術來實現後端邏輯,而是使用了wilddog充當後端。具體關於wilddog的介紹,戳這裏。react
目標:我指望的頁面長這樣,一個簡單的消息列表,下面有個輸入框和提交按鈕,任何人能夠在上面說話,並能夠看到別人說的話,就這麼簡單。
webpack
1. React和Reduxgit
React這麼火,我就很少說了。Redux是一個類flux的應用框架,和flux同樣是單向數據流,目前用來主要是對flux進行了一些優化,如將action變爲簡單的對象,store也是一個簡單的對象樹,引入了reducer來處理action,reducer自己是pure function,調試起來也極爲方便,還能夠配合使用hot-loader以及redux-dev-tool實現time travel調試功能,用起來仍是有點爽爽的感受。github
2. 開始codingweb
"不想看扯淡,只要看源碼的"戳這裏:D。redux
文件目錄是這樣的:後端
項目是使用webpack打包的,也用了dev-server,有興趣的同窗能夠本身看webpack目錄和server.js。websocket
這裏主要關注src下面的內容:app
store建立一個惟一的store,存放項目中全部的數據。
reducers: 初始化store的部份內容,在這裏是個空對象。還有處理store的函數,這裏只有一個init的工做,就是用action中傳過來的chats字段替換當前的state,這裏的業務邏輯對應的是,每當聊天室有新的消息傳過來,都會整個替換當前的聊天內容,這裏可能會有疑問爲何要這樣,主要是由於wilddog傳給個人就是一個完整的列表,後面仔細會介紹wilddog。
const initialState = {
};
export function chat(state = initialState, action) {
switch (action.type) { case INIT_CHAT: return Object.assign({},state,action.chats); default: return state; }
}
action : 只是一個簡單的表示操做動做的對象。
export function init(chats){ return { type : INIT_CHAT, chats }
}
export function getChats(){
return function(dispatch){ ref = new Wilddog("https://firstblood.wilddogio.com/"); ref.on("value", function(snapshot) { console.log(snapshot.val()); dispatch(init(snapshot.val())); }, function (errorObject) { console.log("The read failed: " + errorObject.code); }); }
}
export function postMsg(msg){
return function(dispatch){ var postsRef = ref.child("msgs"); postsRef.push({ date: Date.now(), msg }); }
}
很顯然,除了init是簡單的對象以外,還有兩個相對複雜的函數。這裏用到redux-thunk,其做用就是把一些比較複雜的動做(例如這裏用到的異步操做)封裝到一個action中去,redux-thunk是redux的一個middleware,redux的dispatch沒法處理對象以外的內容,例如函數,將redux-thunk放進去了就能夠了:
import thunkMiddleware from 'redux-thunk';
const createStoreWithMiddleware = compose(
applyMiddleware( thunkMiddleware, logger ), window.devToolsExtension ? window.devToolsExtension() : f => f
)(createStore);
這裏的getChats()首先新建了一個wilddog實例,鏈接我在wilddog上定義好的項目上,
野狗提供的on()函數能夠經過websocket來監聽數據是否發生了變化,正如這裏寫的,每當數據發生變化都會dispatch一次init動做,來將頁面的數據從新渲染。
而postMsg則是將新的消息推到wilddog上。這樣會出發wilddog的數據變化,而後反過來會觸發咱們以前定義在on()回調裏面的內容,及從新獲取數據,渲染頁面。
container/chat.js: 頁面主體的react組件。首先將這個react組件和redux的store關聯起來,這裏用到的react-redux中的connect函數,在註解裏完成了:
@connect( state => state.chat, dispatch => bindActionCreators(actionCreators, dispatch)
)
你們是否還記得咱們以前定義好了獲取頁面初始消息列表的getChats函數,在這裏被調用:
componentDidMount(){ this.props.getChats(); this.setState({ input : "" }); }
讓咱們來關注頁面html的代碼,首先是消息列表:
<List className="msgList" ref="msgList"> <Subheader>Chat</Subheader> { _msgList.map((msg,index)=> <section key = {index} ref="msgItem"> <ListItem leftAvatar = {<Avatar src={require('./files/avatar.png')} />} primaryText = {moment(msg.date).format('YYYY-MM-DD HH:mm:ss')} secondaryText={ <p> {msg.msg} </p> } secondaryTextLines={1}/> <Divider inset={true} /> </section> ) } </List>
循環_msgList來輸出每一條消息,這裏用到List,ListItem是material-ui中的。這個_msgList是從store中取出的:
const { msgs } = this.props; let _msgList = []; for(let i in msgs){ _msgList.push(msgs[i]); }
接下來是輸入框和say按鈕部分的代碼:
<div className="post">
<form onSubmit={this.handleSubmit.bind(this)}> <TextField ref="input" className="input-sec" underlineStyle={inputStyles.underlineStyle} hintText="Say something.." onChange={this.handleChange} value={this.state.input} /> <RaisedButton label="Say" className="postBtn" type="submit"/> </form> </div>
能夠看到是主要是一個表單提交的工做,handleSubmit即表單提交的函數:
handleSubmit = (event)=>{ event.preventDefault(); if(!this.refs.input.getValue())return; this.props.postMsg(this.refs.input.getValue()); this.refs.main.scrollTop = 10000; this.setState({ input : "" }); };
這裏最重要的是this.props.postMsg,調用的是以前定義在action中的postMsg函數完成新增消息的操作。
到目前位置代碼部分就完了,這裏能夠試試demo,我用的wilddog我的免費版,資源有限,別整掛了:P