The reason you are getting a console error saying GetCtxFromView is undefined is because you are trying to call that function before it is loaded and available.
Any Javascript you load on to a page using an inline <script> block will be executed immediately as it's loaded. Meanwhile, all the default/built-in SharePoint Javascript functions you are trying to take advantage of (GetCtxFromView and ExitGrid) are being loaded behind the scenes as SharePoint loads all of its many Javascript files where all of those functions are defined (init.js, sp.init.js, sp.core.js, sp.runtime.js, sp.js, etc., etc.). The loading process for all those scripts is complicated and takes a bit of time. So it's very likely that your script gets executed well before GetCtxFromView is actually available to be called.
One thing you can try to do is use _spBodyOnLoadFunctionNames (which is available very early in the page load process) to tell SharePoint you have a function you want to be executed once the page body is loaded (kind of similar to jQuery's $(document).ready()). This will delay the execution of your function, hopefully long enough that GetCtxFromView is available when you want it.
To do that, you need to put your code inside a named function, and then push() the function name as a string on to the _spBodyOnLoadFunctionNames collection:
<script type="text/javascript"> function showHideButtonByMode() { var gridinfo = GetCtxFromView(window['WPQ2SchemaData'].View); if (gridinfo.inGridMode) { //in grid mode document.getElementById("lynk").style.display = 'block'; } else { //in normal mode document.getElementById("lynk").style.display = 'hidden'; } } _spBodyOnLoadFunctionNames.push('showHideButtonByMode'); </script>
Now, as I said, the way SharePoint loads its background scripts is complicated and takes a little while, so that may not even be enough of a delay. If it's not, you could try something a bit more extreme, which is to tell SharePoint not to execute your function until a specific SharePoint Javascript file has been loaded. You can do that by using the built in ExecuteOrDelayUntilScriptLoaded function (which is also available very early in the page load process). To do that, you would replace the _spBodyOnLoadFunctionNames.push() line in the above example with:
ExecuteOrDelayUntilScriptLoaded(function () { showHideButtonByMode(); }, 'sp.js');
This is essentially telling SharePoint "wait until the file sp.js is loaded, and then execute this anonymous function", and then inside the anonymous function you are calling your named function. You could also do it like
ExecuteOrDelayUntilScriptLoaded(showHideButtonByMode, 'sp.js');
but to me it makes it a bit easier to see/understand what is going on with the anonymous function, plus, if you have to add other steps, you can do it inside the anonymous function. I guess you could also do it by putting all of your code inside the anonymous function, like:
<script type="text/javascript"> ExecuteOrDelayUntilScriptLoaded(function () { var gridinfo = GetCtxFromView(window['WPQ2SchemaData'].View); if (gridinfo.inGridMode) { //in grid mode document.getElementById("lynk").style.display = 'block'; } else { //in normal mode document.getElementById("lynk").style.display = 'hidden'; } }, 'sp.js'); </script>
Now, last point - these last variations on the example using ExecuteOrDelayUntilScriptLoaded are all using sp.js as the script file to wait for. That's making the assumption that GetCtxFromView is defined in sp.js or one of its dependencies that gets loaded earlier.
I don't know for sure that that function is defined in that file, so even that might not work. If it doesn't, what you would need to do is do the research to find out what SP Javascript file has GetCtxFromView, and then change where you refer to sp.js to refer to that other Javascript file, to make sure that you are waiting for the file to load that holds the function definition for the function you are tying to use.