基於React,Redux以及wilddog的聊天室簡單實現

本文主要是使用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

相關文章
相關標籤/搜索