Tag Archives: JavaScript

React.js and MobX: Escape the Redux trap

I have seen React in action for the first time in relatively complex legacy application. There were some attempts to develop new functions using React and, of course, Redux. Because everyone is using that combination. It is the clear, cool way. Hm…

notsure

I fell in love with React quickly but with Redux it was not so hot. Alex Dixon wrote great article about his problems with Redux and functional programming in JavaScript. TLDR:

  • You never know whether you have plain JS object or Immutable.js object under your hands.
  • If you are not using Immutable.js then you still should know whether object you have can be mutated or not.
  • In every file you have to manually import libraries like Immutable or Lodash.

I had those issues plus:

  • It was real pain to describe complex change you would like to perform on immutable state within store. Like add 6th item into array, remove 3 different keys from map, etc.
  • For doing even simple things you have to modify code in multiple files. One often do a hack instead of nice solution.
  • Problems with using multiple stores. I still had feeling that I should not store state of form in global store. Local data should be local, right?
  • Same store is used during navigation without page reload. It is hard to clean everything properly.
  • React-Redux library is doing incredible magic I was never able fully understand.
  • Using Promises just made thing worse.
  • I still had feeling that if I have to reorganize store structure I will got mad.

Then, out of blue sky, I have found MobX. And I realized that I found great React’s partner.

thinking

I can have multiple stores – one that holds application state (selected language, global formatting settings), second that holds form state and handles communication with server, third for caching currency conversions, etc. This stores are available through React context – therefore their presence is checked by React using contextTypes definition. You can freely move components in hierarchy as long as you assure that proper stores are in context.

I still have certain level of immutability because MobX checks that no change is done during processing previous change.

Adding functionality is deadly simple. You have two classes – component and store.

Because store is single purpose and is object of class, it is quite easy to determine what you can do with it. If there is method, try to call it. Compare that with searching for proper Redux action.

Despite I have never use truly functional programming language I highly utilize lambda expressions (Ruby, Java 8, JavaScript), enjoy passing function as parameter and since then my usage of class inheritance dropped by 90% 🙂 In Java I employ Immutables, Jooq and high percentage of methods I write are static ones. So I consider myself open minded in functional programming area. That hopefully gives me some credit to have strong feeling that combination of React and Redux is simply wrong. MobX and React, on the other hand, are just great combination. At least for me 😉

 

 

 

 

text-overflow: ellipsis from left

Today I needed to put one line of possibly long text into table. So text may be wider than table cell. In that case client needs to see end of that text because it contains more important data. What is worse my cell width depends on client resolution so I cannot trim text on server. Here is simple illustration:

 

overflow

There is CSS text-overflow property that can end text that can visualize by ellipsis (“…”) that text is longer than element size so it overflows element and is hidden. That is fine for text has more important part on the beginning. But what about text that has more important part on the end? It would be better to show ellipsis on left side, right?

Unfortunately it is not possible nowadays, there is only outdated draft of such function done by W3C. It would allow you to define behavior for both sides of text.

Other possibility are various CSS hacks, like this one, or this one, or … They are based on nasty tricks and suffer for many problems. One is common to all of them – they are using clipping by rectangle so text which is on border is clipped too. For example it cuts letter O so it looks like bracket. That is confusing, so this way was not feasible for me. See first example on image above.

So there is only one option. Yes, JavaScript :-/ My sample is using JQuery and works like this:

  1. Adds hidden element whose width is same as maximal text width into page
  2. Walks through all elements that may possibly overflow
  3. Put text (stored in data- attribute) that should be displayed into hidden element
  4. Shorten it by one letter as long as text is longer than hidden element
  5. Put shortened text into target element
  6. Possibly react on resize/ready/… events

Here is the code (download from github):

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Left text-overflow test page</title>
		<script src="https://code.jquery.com/jquery-1.12.0.min.js"></script>

		<script>
		    //on document ready
			$(document).ready(function() {
	            shortenTexts();
            });

            //on widow resize
            $(window).resize(function() {
	            shortenTextsDelayed();
            });

            //wait for rendering done
            function shortenTextsDelayed() {
	            window.setTimeout(shortenTexts, 100);
            }

            function shortenTexts() {
	            //get ruler
	            var measureBox = $("#ruler");
	            var measureBoxSpan = measureBox.children("span").first();
	
	            //iterate over texts that should be shortened
	            $("div.shorten").each(function(index, element){
	                //target span
		            var span = $(element).children("span").first();
		            
		            //full text
		            var text = $(element).data("original");
		
		            //init by full text
		            measureBoxSpan.text(text);
		
		            //while span in ruler is bigger than ruler
		            while (text.length>0 && measureBoxSpan.width()>measureBox.width()) {
		                //shorten string
			            text = text.substring(1);
			
			            //set new text
			            measureBoxSpan.text("…"+text);
		            }
		
		            //set target text by succeeded text
		            span.text(measureBoxSpan.text());
	            });
            }
		</script>

		<style>
		    body {
		        padding: 0px;
		        margin: 0px;
		    }
		
		    body > div {
		        max-width: 90%;
		    
		        font-size: 25px;
		        overflow: hidden;
		        white-space: nowrap;
		        
		        border: 1px solid gray;
		        
		        padding: 5px;
		    }
		    
		    div.ellipsis {
		        text-overflow: ellipsis;
		    }
		    
		    #ruler {
		        position: absolute;
		        visibility: hidden;
		    }
		</style>
	</head>

	<body>
	    
	    <h1>Implicit</h1>	
		<div>
		    <span>
		        This is sooo long text. Probably it will overflow, right? 
		        But maybe, maybe there will be extremely important information 
		        that you should not miss in the end. Information that you 
		        should not miss. The ultimate answer. Curious? Now I will 
		        count 1 2 3 4 5 6 7 8 9. Really? I do not believe you! 
		        REALLY! So the ultimate answer is: 42!
		    </span>
		</div>
		
		<h1>text-overflow: ellipsis</h1>
		<div class="ellipsis">
		    <span>
		        This is sooo long text. Probably it will overflow, right? 
		        But maybe, maybe there will be extremely important information 
		        that you should not miss in the end. Information that you 
		        should not miss. The ultimate answer. Curious? Now I will 
		        count 1 2 3 4 5 6 7 8 9. Really? I do not believe you! 
		        REALLY! So the ultimate answer is: 42!
		    </span>
		</div>
		
		<h1>JavaScript shortening from left</h1>
		<div id="ruler"><span> </span></div>		
		<div class="shorten" data-original="This is sooo long text. Probably it will overflow, right? 
		        But maybe, maybe there will be extremely important information 
		        that you should not miss in the end. Information that you 
		        should not miss. The ultimate answer. Curious? Now I will 
		        count 1 2 3 4 5 6 7 8 9. Really? I do not believe you! 
		        REALLY! So the ultimate answer is: 42!">
		    <span> </span>
		</div>
	</body>

</html>

Result looks like, try to play with browser window size – overflow should adapt:
output

Enjoy!