Mark Oliver's World

Posted: 28/03/2021

Getting Twitter To Work

Hello again, in How I Built This Blog Part 3, we were unable to get Twitter to render the timeline on our page, nor could we get it reliably showing the "Tweet me" button.

The "Tweet me" button.

Its simple really, we add

            <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
            
          

and

            <p><a href="https://twitter.com/intent/tweet?screen_name=MicbOliver&ref_src=twsrc%5Etfw" class="twitter-mention-button" data-show-count="false">Tweet to @@MicbOliver</a></p>
            
          

and we should see a "Tweet me" button.

However, this does not always render.

Sometimes it shows on a refresh, sometimes on an initial load, sometimes never.

So we forced Twitter to load with an

            await JSRuntime.InvokeVoidAsync("twttr.widgets.load");
            
          

in the OnAfterRenderAsync() call of the component. The lifecycle docs say this is sensible.

This makes it work "sometimes".
So what about a

            this.StateHasChanged();
            
          

aswell.

Nope! DOH!

This part of the documentation concerns me:

            Even if you return a Task from OnAfterRenderAsync, the framework doesn't schedule a further render cycle for your component once that task completes. This is to avoid an infinite render loop. This is different from the other lifecycle methods, which schedule a further render cycle once a returned Task completes.
            
          

Oddly, moving that code out of the MainLayout.razor file and directly into the component that is rendering the Twitter content gives me the result I need. But why?
The component is going to be rendered within the MainLayout, so why would that help? It should still have scope right????

Ok, lets move the Twitter invoking code to its own component, and put that in the page that needs it.

yes that works ok.

So lets have a component whose job is to say: "Come and tweet me" with the twitter mention button, I can then bundle it all up in one thing, and include the component where I want.

Awesome that is one down!

Timeline display

So when I add in this line to Embed my timeline on the page:
<a class="twitter-timeline" data-width="500" data-height="600" href="https://twitter.com/MicbOliver?ref_src=twsrc%5Etfw">Tweets by @@MicbOliver</a>

it all works fine, until I navigate to another page.

Then I get these errors

            crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]       Unhandled exception rendering component: Cannot read property 'removeChild' of null       TypeError: Cannot read property 'removeChild' of null  Microsoft.JSInterop.JSException: Cannot read property 'removeChild' of null TypeError: Cannot read property 'removeChild' of null  blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]       Unhandled exception rendering component: No element is currently associated with component 22       Error: No element is currently associated with component 22
            
          

This suggests that Blazor is trying to cleanup the DOM that the Twitter javascript has changed after render.

I currently have no idea what this is, so i'll come back to it tomorrow.
Please tweet me if you have any ideas.

UPDATE:
Well I sent a tweet out into the world, and some lovely people tried to help.

They suggested several things, but the solution was really simple, and thanks to Kristoffer Strube it now works.

He said, that I just need to put the twitter link in a paragraph tag, and then it wont get confused. He said:

            Also, a fix for the last problem is to encapsulate the timeline in a paragraph or div tag since the Twitter JS removes the anchor tag which is the outermost tag in the page/component for which Blazor needs a reference.
            
          

You can see it working on the front page !

Simple really. Thanks so much Kristoffer!


Thanks for reading this post.

If you want to reach out, catch me on Twitter!

I am always open to mentoring people, so get in touch.