React Tips: 4 – Propagating State

One thing that’s worth remembering about React is that when you’re updating state, only the Render method gets re-executed.

It’s easy (as I did) to fall into the trap of doing something like this:

    const myStyle = {
        background: this.props.backgroundFlag == 1 ? "blue" : "yellow",
        display: 'inline-block',
        height: '100%',
    }

    public render() {
        return <>
            <div className="myDiv" style={myStyle}>
        </>
    }

Imagine that this.props.backgroundFlag is actually the state of the containing component; when you change it, you would expect your component to reflect your change. However, in the case above, what will actually happen is nothing – because only the render method is re-evaluated when the virtual DOM changes.

To correct this, you need whatever needs to be re-evaluated inside the render method; for example:

    public render() {
	    const myStyle = {
	        background: this.props.backgroundFlag == 1 ? "blue" : "yellow",
	        display: 'inline-block',
	        height: '100%',
	    }

        return <>
            <div className="myDiv" style={myStyle}>
        </>
    }

UWP using Unity and EF Core and Sqlite

If you intent to use IoC with a UWP application, there are a lot of options. Most of them come with MVVM packages, like MVVM Cross. These are excellent packages – I’ve used MVVM Cross and MVVM Light myself and can highly recommend them.

However, if you didn’t want all that baggage, how would you implement a very simple IoC system in UWP?

In this example, I’m using Unity, however, I believe this will work for any IoC container. I’m also using the IoC container to resolve a View Model – but you don’t need to use View Models (although IMHO, it makes your life so much easier.)

Secondly, I’ll be showing how to use Ef Core with your UWP app. This sounds very trivial, but there’s a bit of fiddling about to get it to work.

Entity Framework Core Set-up

In my project, I’ve separated the data access layer, but you don’t need to do that. Start by creating a data context:

public class MyDbContext : DbContext
{
    public DbSet<Data> MyData { get; set; }
 
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Data Source=mydata.db");
    }
}

You’ll need the following packages:

Install-Package Microsoft.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.Design
Install-Package Microsoft.EntityFrameworkCore.Tools
Install-Package Microsoft.EntityFrameworkCore.Sqlite

You’ll also need to create a console application – why? Because you can’t use any of the EF tools with UWP! If you set your UWP app as the start-up and create your migration, you’ll get this error:

Startup project ‘SendMessage.UWP’ is a Universal Windows Platform app. This version of the Entity Framework Core Package Manager Console Tools doesn’t support this type of project.

Set the console app as startup and add the migration:

Add-Migration "InitialDbCreate"

Don’t worry about updating the DB, we’ll get the app to do that (it just can’t use the tools, but it can perform a migration.)

UWP

From a new, blank, UWP app; in app.xaml.cs:

sealed partial class App : Application
{
    public static IUnityContainer Container { get; set; } = new UnityContainer();
 
    /// <summary>
    /// Initializes the singleton application object.  This is the first line of authored code
    /// executed, and as such is the logical equivalent of main() or WinMain().
    /// </summary>
    public App()
    {
        this.InitializeComponent();
        this.Suspending += OnSuspending;
 
        using (var db = new MyDbContext())
        {
            db.Database.Migrate();
        }
        
        Container.RegisterType<MainViewModel>();
    }

We’re creating a static UnityContainer in App.Xaml.cs. Register the type (in this case a MainViewModel, but it could as easily be an interface).

The next step is resolving the interface. Unfortunately, because of the way that the UWP navigate works, Unity won’t perform constructor injection for us. A little trick around this is to create a parameterless constructor and have that call the injected constructor. It’s not quite constructor injection, but semantically it’s the same thing. Here’s the code from my MainPage.xaml.cs:

public sealed partial class MainPage : Page
{
    public MainPage() : this(App.Container.Resolve<MainViewModel>()) { }
 
    public MainPage(MainViewModel mainViewModel)
    {
        this.InitializeComponent();
 
        this.DataContext = mainViewModel;
    }
}

That’s pretty much it; you can run this, and it’ll migrate the data, and resolve the dependency.

References

https://docs.microsoft.com/en-us/ef/core/get-started/uwp/getting-started

React Tips: 3 – Cloning a React Repository

After you clone a React repository, running npm start may give this error:

‘react-scripts’ is not recognized as an internal or external command

The reason, as explained here, is that you need to run:

npm install

This should be run inside the directory that you clone. For example:

git clone https://github.com/pcmichaels/react-demos.git
cd react-demos
npm install
npm start

React Tips: 2 – Binding an Event Handler

Example code here.

When dealing with any flavour of Javascript, sooner or later, you’re going to come across the this problem. The issue being that, what this means, depends on where you are. This can be a particularly prevalent issue with React; imagine the following code:

onMouseUp={this.onMouseUp}

In onMouseUp, you might want to affect the state in some way:

private onMouseUp(e) {
    this.setState({
        dragging: false
    });

If you run this, you’ll likely get the following error:

TypeError: this is undefined

I think you’ll agree, a clearer message couldn’t be had.

Binding

The answer to the problem that I’ve so eloquently posed here, is binding. Essentially, you simply tell your local function to know about this:

onMouseUp={this.onMouseUp.bind(this)}

This does fix the problem; now the method will execute without error. However, what we are actually doing here is creating a new function every time the page is rendered. To circumvent this you can leave the original code as it was:

onMouseUp={this.onMouseUp}

But then bind the method in the constructor:

constructor(props) {
    super(props);

	this.onMouseUp = this.onMouseUp.bind(this);

As an aside, if you happen to see the following error:

Argument of type ‘this’ is not assignable to parameter of type ‘MouseEvent‘.

You’ve likely missed the .bind; for example:

this.onMouseUp = this.onMouseUp(this);

Ask me how I know!

Class Properties

Another, newer (and IMHO much cleaner), way around this is the following syntax:

onMouseDown = (e) => {
    console.log('onMouseDown');
    this.setState({
        dragging: true
    });
}

This doesn’t require any binding.

References

https://reactjs.org/docs/faq-functions.html

React Tips: 1 – Starting React on a Different Port

I came up with an idea to start a series of posts on React that offers small tips on things you can do, errors that you might get, and anything else that future me might find useful.

I started by creating a new react app. The intention being that I would have a reference repository on GitHub.

The first part of this concerns starting react on a different port.

Why?

There are a couple of reasons that you may choose to do this, but one is to get around the issue when running:

npm start

Something is already running on port 3000

How

Have a look in your project for a file called package.json. In there, you should see something like this:

{ 
"name": "react-demos",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},

In the start section, you can add the port:

{ 
"name": "react-demos",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1"
},
"scripts": {
"start": "set PORT=3005 && react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},

The default port is 3000, so if you don’t specify a port, it will always try to start on 3000.

What if I don’t want to change the port / Why won’t react die?

You could try the following command is bash:

taskkill -F -IM node.exe

It should kill all of your React processes.

References

https://github.com/facebook/create-react-app/issues/1083

https://stackoverflow.com/questions/45544145/how-stop-after-running-react-scripts-start

Adding Logging to Client Side Blazor

Whilst there are some pre-built libraries for this, I seemed to be getting Mono linking errors. What finally worked for me was to install the pre-release versions of:

Install-Package Microsoft.Extensions.Logging -Version 3.0.0-preview6.19304.6
Install-Package Microsoft.Extensions.Logging.Console -Version 3.0.0-preview6.19304.6

Now, in your View Model, accept the Logger:

public MyViewModel(ILogger<MyViewModel> logger)

Then you can log as normal:

_logger.LogInformation("Hello, here's a log message");

You should now see the debug message in the F12 console.

You might be wondering why you don’t need to explicitly inject the logging capability; the reason is that:

BlazorWebAssemblyHost.CreateDefaultBuilder()            

Does that for you.

Using View Models in Blazor

Being new to Blazor (and Razor), the first thing that tripped me up was that the view seemed divorced from the rest of the application. In fact, this is actually quite a nice design, as it forces the use of DI.

For example, say you wanted to create a View Model for your view, you could register that ViewModel in the Startup:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<MyViewModel, MyViewModel>();
        }

Note here that you don’t need an interface. If you’re only creating an interface for the purpose of this then that abstraction provides no benefit. That isn’t to say there may not be a reason for having an interface, but if you have one and this is the only place it’s used, you probably should reconsider.

The views in Razor / Blazor (at the time of writing) are *.razor files. In order to resolve the dependency inside the view, you would use the following syntax:

@page "/"
@inject ViewModels.MyViewModel MyViewModel

(Note that @page “/” is only in this snippet to orientate the code.)

You can call initialisation in the view model using something like:

@code {

    protected override async Task OnInitAsync()
    {
        await MyViewModel.Init();
    }    
}

And, within your HTML, you can reference the view model like this:

<div>@MyViewModel.MyData</div>

Magic. Hopefully more to come on Blazor soon.

Creating a Car Game in React – Part 5 – Levels and Time

This is the fifth part of a series (that began here).

In the last post, we added the concept of score. The car now can collect cups while avoiding trees; however, we don’t have any concept of what happens when there are no cups left.

In this post, we’ll add levels to the game, so that when you’ve collected all the cups, you move up. We’ll also introduce a time limit to make it progressively harder (as it currently stands, it’s not much of a challenge to collect the cups because you can take all day).

The source for this post is here. Again, not everything is in the post, so please refer to the repository.

Levels

Because we are creating levels, we’ll need to track the level that we’re on, so a new state property is in order:

this.state = {
	playerX: 100,
	playerY: 100,
	windowWidth: window.innerWidth,
	windowHeight: window.innerHeight,
	playerMomentum: 0,
	playerRotation: 0,
	playerVelocityX: 0,
	playerVelocityY: 0,
	playerLives: 3,
	playerCrashed: false,
	gameLoopActive: false,
	message: "",
	score: 0,
	level: 1,
	cupCount: 1, 
	remainingTime: 0
};

If you’ve followed this through from this first post, you may be asking yourself: “Is he ever going to refactor and clean this up!?”

To which I confidently respond:

“Probably!”

Anyway, you’ll notice that we have the level, the score, the time and the cup count. Advancing through the levels is conceptually just a number; here’s the code that completes a level:

completedLevel() {
	if (this.state.level >= 10) {
		this.updateMessage("Congratulations, you've completed the game");
	} 
	this.startLevel(this.state.level + 1);
}

startLevel is a slight refactor, which essentially sets the cup count and level to the new value – we’ll come back to that shortly.

You can only complete a level by collecting enough cups, so the trigger should be in the cup collection:

collectedCup(key) {
	this.setState({ 
		score: this.state.score + 1 
	});
	this.cups = this.cups.filter(cup => cup.key != key);
	this.updateMessage("Collected cup");
	if (this.cups.length == 0) {
		this.completedLevel();
	} 
}

As soon as we’re down to 0 cups, we call completedLevel.

Time

Now it’s time to have a look at the startLevel code:

startLevel(level) { 
	this.setState({
		level: level,
		cupCount: level * 2 
	}); 
	this.obstacles = this.buildObstacles(); 
	this.cups = this.placeCups();
	this.resetCarPosition();
	this.totalLevelTimeMS = (this.TOPLEVEL - (this.state.level - 1)) * 60 * 1000
	let startLevelTimeMS = (new Date()).getTime();
	this.endLevelTimeMS = startLevelTimeMS + this.totalLevelTimeMS; 
}

We’re working out when the user is out of time, and storing that in endLevelTime. Note that none of these are in state variables – the only state variable is in updated in the game loop:

let remaining = (this.endLevelTimeMS - (new Date()).getTime()) / 1000;
if (remaining <= 0) {
	this.updateMessage("Out of time!");
	this.playerDies();
}
this.setState({
	remainingTime: Math.round(remaining)
}); 

This is at the end of the game loop: we’re updating the remainingTime state variable, but first, we calculate it and, if it’s zero, the player dies (loses a life).

We need to tweak the code for the player dying, because otherwise the timer will never get reset:

playerDies() { 
	this.setState({
		playerLives: this.state.playerLives - 1,
		gameLoopActive: false
	});
	if (this.state.playerLives <= 0) {
		this.initiateNewGame();
	} else {
		this.startLevel(this.state.level);
	}
	this.repositionPlayer();
	this.setState({ 
		playerCrashed: false,
		gameLoopActive: true
	});
}

The last part is to make the time look a bit better with another of my patented icons. GameStatus.jsx should now return the following:

    return (      
        <div className="flex-container" style={flexStyle}>
            <label style={labelStyle}>
                Lives Remaining: {props.Lives}
            </label>
            <label style={labelStyle}>
                Score: {props.Score}
            </label>
            <label style={labelStyle}>
                Level: {props.Level}
            </label>            
            
            <div style={containerStyle}>  
                <img src={clockImg} style={imgStyle} />
                <div style={textDivStyle}>{props.RemainingTime}</div>
            </div>

            <label style={labelStyle}>
                {props.Message}
            </label>
        </div>  
    );

There are some new styles here so that the time appears over the clock icon:

    const containerStyle = {
        position: 'relative',
        textAlign: 'center',
        color: 'red'
    }

    const textDivStyle = {        
        position: 'absolute',
        top: '50%',
        left: '50%',
        transform: 'translate(-50%, -50%)',
        zIndex: 1,
        fontWeight: 'bold'
    }

    const imgStyle = {
        width: '100%',
        zIndex: 0
    }

In the next part, we’ll implement a high score table.

Creating a Car Game in React – Part 4 – Score

This is the fourth part of a series (that began here). So far, we have a game where you can whizz around the screen avoiding trees. This effectively encompasses most aspects of a game of this type; that is, you can move, and there is a something preventing you.

The next step is to introduce something for the player to try to do, and give a score based on that. In our case, our player is going to try and collect cups – as per the original game. The asset I’ve created for the cup is here. For anyone following this series, you may have noticed that my artwork is a little… crap.

The source for this post is here.

Cups

The first thing that we’ve done here is added some code to place a few cups around the screen; the code for this was essentially the same as build obstacles:

placeCups() {
	let cups = [];
	const cupCount = 1;
	for (let i = 1; i <= cupCount; i++) {
		const centreX = Math.floor(Math.random() * this.state.windowWidth) + 1;
		const centreY = Math.floor(Math.random() * this.state.windowHeight) + 1; 
		cups.push(<GameItem key={i} image={cupImg} centreX={centreX} centreY={centreY} width={this.spriteWidth} height={this.spriteHeight} itemType={2} />);
	}
	return cups;
}

In a later post, I hope to do a full refactor, but for now, we have a separate function. This is rendered in the same way as the obstacles:

render() { 
	return <div onKeyDown={this.onKeyDown} tabIndex="0">
		<GameStatus Lives={this.state.playerLives} Message={this.state.message} Score={this.state.score} />
		
		<Background backgroundImage={backgroundImg}
		windowWidth={this.state.windowWidth} windowHeight={this.state.windowHeight} /> 
		
		<Car carImage={this.state.playerCrashed ? brokenCarImg : carImg} 
		centreX={this.state.playerX} centreY={this.state.playerY} 
		width={this.spriteWidth} height={this.spriteHeight} 
		rotation={this.state.playerRotation} /> 
		
		{this.obstacles} 
		
		{this.cups} 
	</div>
}

Collecting cups

In order to collect something, the player must collide with it. We need to change the collision code slightly to make it a little more re-usable:

detectAnyCollision(rect1) { 
	// Have we crashed or left the screen
	if (this.detectOutScreen(rect1)) {
		return true;
	}
	let collided = this.detectGameItemCollision(this.halfWidth, this.halfHeight, rect1, this.obstacles);
	if (collided !== undefined) {
		return true;
	}
	return false;
}

detectGameItemCollision(halfWidth, halfHeight, rect1, gameItemList) {
	const collided = gameItemList.find(a => {
		var rect2 = {
			x: a.props.centreX - halfWidth, y: a.props.centreY - halfHeight,
			width: this.spriteWidth, height: this.spriteHeight
		};
		return (this.detectCollision(rect1, rect2));
	}); 
	return collided;
}

As you can see, we now have a function that returns the item that we collided with, rather than a simple boolean. We then use this at the end of the game loop to determine whether we collided with a cup:

// Check for collected cup
const item = this.detectGameItemCollision(this.halfWidth, this.halfHeight, rect1, this.cups);
if (item !== undefined) {
	this.collectedCup(item.key);
} 

Score

There’s little point in zooming around collecting cups, if there’s no permanent record, so we need to add a score. Let’s start with a state variable in game.jsx:

this.state = {
	playerX: 100,
	playerY: 100,
	windowWidth: 1500,
	windowHeight: 1500,
	playerMomentum: 0,
	playerRotation: 0,
	playerVelocityX: 0,
	playerVelocityY: 0,
	playerLives: 3,
	playerCrashed: false,
	gameLoopActive: false,
	message: "",
	score: 0
};

And here’s the collectedCup function we mentioned a second ago:

collectedCup(key) {
	this.setState({ score: this.state.score + 1 });
	this.cups = this.cups.filter(cup => cup.key != key);
	this.updateMessage("Collected cup");
}

All we’re doing here is simply updating the score and then removing that cup from the list.

The final part is to display the score on the screen; let’s have a look at our updated GameStatus.jsx:

function GameStatus(props) {
	const flexStyle = {
		display: 'flex',
		position: 'absolute',
		zIndex: 1,
		margin: 20,
		justifyContent: 'center',
		alignItems: 'center',
		width: '100%'
	};
	const labelStyle = { 
		zIndex: 1,
		margin: 50
	};
	return ( 
		<div className="flex-container" style={flexStyle}>
			<label style={labelStyle}>
				Lives Remaining: {props.Lives}
			</label>
			<label style={labelStyle}>
				Score: {props.Score}
			</label>
			<label style={labelStyle}>
				{props.Message}
			</label>
		</div> 
	);
}

As you can see, we’re just displaying the score as part of the status.

In the next post, we’ll have a look at the concept of levels, and introduce a time limit.

Reference

https://www.w3schools.com/css/css3_flexbox.asp

The “LegacyFrameworkPackages” parameter is not supported by the “ResolveFrameworkReferences” task

I got this error recently while updating a project that I’m working on. It had been ported from WinForm to .Net Core 3.0, and worked fine – but suddenly I started getting errors where it claimed to not know what Form was. The output showed the error:

The “LegacyFrameworkPackages” parameter is not supported by the “ResolveFrameworkReferences” task

Unbeknownst to me, MS have changed the namespace for desktop apps; where previously your csproj might look like this:

<Project Sdk="Microsoft.NET.Sdk">
 
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <LangVersion>8.0</LangVersion>
    <NullableReferenceTypes>true</NullableReferenceTypes>
    
    <AssetTargetFallback>uap10.0.18362</AssetTargetFallback>
    <UseWindowsForms>true</UseWindowsForms>
  </PropertyGroup>

It now needs to look reference the WindowsDesktop SDK:

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">