简体   繁体   English

如何使用react / redux设计多标签聊天?

[英]How to design a multi tab chat with react/redux?

I am developing a chat platform to take multiple chats and he can switch between the chats. 我正在开发一个聊天平台以进行多个聊天,他可以在聊天之间进行切换。

var MessageList = React.createClass({
   render() {
       return (
          <div className='messages'>
          <h2> Conversation: </h2>
          {
              this.props.messages.map((message, i) => {
                  return (
                      <Message
                          key={i}
                          user={message.user}
                          text={message.text}
                      />
                  );
              })
          }
      </div>
       );
}})

Let's just take an example of message list which will change when user switches the chat tab. 让我们仅以消息列表为例,当用户切换聊天选项卡时,消息列表将更改。 Re rendering the same component with new messageList with respect to the chat makes sense but when there are 100 other component changes like this when there is a switch in chat, then there will be lot of repainting/rendering.(I know only diff will be changed in the dom but still.) 就聊天而言,使用新的messageList重新渲染相同的组件是有意义的,但是当聊天中有切换时,当像这样进行100个其他组件更改时,那么将会有很多重绘/渲染。(我知道只有diff会在dom中进行了更改,但仍然如此。)

I would like to create different elements for different chats and hide and show them based on active chat. 我想为不同的聊天创建不同的元素,并根据活动聊天隐藏和显示它们。 But react works under a single dom and replaces the dom with what's returned where it has been attached to. 但是react在单个dom下工作,并且将dom替换为已附加的dom。

React.render(<ChatApp/>, document.getElementById('app'));

Can anyone help me up with the design here? 有人可以在这里帮助我进行设计吗?

Thanks in advance. 提前致谢。

 var Tabs = React.createClass({ displayName: 'Tabs', propTypes: { selected: React.PropTypes.number, children: React.PropTypes.oneOfType([ React.PropTypes.array, React.PropTypes.element ]).isRequired }, getDefaultProps: function () { return { selected: 0 }; }, getInitialState: function () { return { selected: this.props.selected }; }, shouldComponentUpdate(nextProps, nextState) { return this.props !== nextProps || this.state !== nextState; }, handleClick: function (index, event) { event.preventDefault(); this.setState({ selected: index }); }, _renderTitles: function () { function labels(child, index) { var activeClass = (this.state.selected === index ? 'active' : ''); return ( <li key={index}> <a href="#" className={activeClass} onClick={this.handleClick.bind(this, index)}> {child.props.label} </a> </li> ); } return ( <ul className="tabs__labels"> {this.props.children.map(labels.bind(this))} </ul> ); }, _renderContent: function () { return ( <div className="tabs__content"> {this.props.children[this.state.selected]} </div> ); }, render: function () { return ( <div className="tabs"> {this._renderTitles()} {this._renderContent()} </div> ); } }); var Pane = React.createClass({ displayName: 'Pane', propTypes: { label: React.PropTypes.string.isRequired, children: React.PropTypes.element.isRequired }, render: function () { return ( <div> {this.props.children} </div> ); } }); var App = React.createClass({ render: function () { return ( <div> <Tabs selected={0}> <Pane label="Tab 1"> <div>This is my tab 1 contents!</div> </Pane> <Pane label="Tab 2"> <div>This is my tab 2 contents!</div> </Pane> <Pane label="Tab 3"> <div>This is my tab 3 contents!</div> </Pane> </Tabs> </div> ); } }); ReactDOM.render(<App />, document.querySelector('.container')); 
 * { box-sizing: border-box; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; } body { font: 300 14px/1.4 'Helvetica Neue', Helvetica, Arial, sans-serif; background: #eee; margin: 0; padding: 0; } .tabs { margin: 25px; background: #fff; border: 1px solid #e5e5e5; border-radius: 3px; } .tabs__labels { margin: 0; padding: 0; } .tabs__labels li { display: inline-block; } .tabs__labels li a { padding: 8px 12px; display: block; color: #444; text-decoration: none; border-bottom: 2px solid #f5f5f5; } .tabs__labels li a.active { border-bottom-color: #337ab7; } .tabs__content { padding: 25px; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div class="container"></div> 

You are saying redux, so I'll try to give some insight but too lazy to provide any code, since it'll be too big / complex. 您是在说redux,所以我将尽力提供一些见解,但由于提供的代码太大/太复杂,因此懒得提供任何代码。

Beforehand, if needed, you can use normalizr when handling with nested JSON format since redux love to be immutable and nested makes it harder to be immutable. 事先,如果需要,您可以在使用嵌套JSON格式进行处理时使用normalizr ,因为redux爱是不可变的,而嵌套则使它变得更不可变。

The reducers: 减速器:

chats { userid:"", message:"", time:"" },
users { userid:"", name:"" },
app { selectedUserId:"" }

Now, the number of tabs to be rendered / displayed is equals to number of users. 现在,要呈现/显示的选项卡数量等于用户数量。 The selected tab is based on app.selectedUserId . 选定的选项app.selectedUserIdapp.selectedUserId The message rendered in panel will be chats, which userid equals app.selectedUserId . 面板中呈现的消息将是聊天,其userid等于app.selectedUserId Some snippet: 一些片段:

var lo = require('lodash');
var selectedChats = lo.filter(this.props.chats, k => k.userid == app.selectedUserId);

var messagesDom = selectedChats.map(k => <MessageLine chat={k});
var chatTabsDom = this.props.users.map(k => <ChatTab userid={k.userid} className={ k.userid == app.selectedUserId ? "active" : "" }> );

return <div>
  <Tabs>{chatTabsDom}</Tabs>
  <Messages>{messagesDom}</Messages>
</div>;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM