Building a React Front-End for my AWS Lambda Sudoku Solver

DZone 's Guide to

Building a React Front-End for my AWS Lambda Sudoku Solver

Learn how to build your own AWS Lambda sudoku solver with React!

· Cloud Zone ·
Free Resource

Over the past few months, I built an implementation of Donald Knuth’s Algorithm X using Dancing Links in Java to solve Sudoku puzzles.

This was a fascinating exercise in itself (you can read more my experience here), but the next logical step would be to package it up in a way to share it online.

Since I’m pursuing my AWS certifications right now, one interesting and low-cost approach to host the Solver implementation is to package it as an AWS Lambda. Sudoku Solver as a Service? Done. I exposed it through AWS API Gateway. It accepts a request payload that looks like this:


and returns a response with a solution to the submitted puzzle request like this:


The request and response payloads are an array of Strings, where each item represents a String of values concatenated together for one row in the grid, with ‘.’s for unknowns.

I’m still learning React as I go, and while building this front-end for my Lambda Sudoku Solver, I learned some interesting things about React and JavaScript. The source for the app is shared here.

I used Flux to structure the app, so the main parts of the app are:

  • A main, high-level Container component
  • CellComponent that renders each cell in the Sudoku grid
  • An Action that handles the interaction with AWS Lambda
  • Store that holds the results from calling the Lambda

I don’t want to focus on the pros and cons of using React or Flux (and this is not intended to be a how-to on building an app using React) as there were some other specific issues I ran into that were interesting learning opportunities. A couple of these I already captured in separate posts, so I’ll include these links below.

Iteration 1: onChange Handler Per Row

My first approach to maintaining the state for the display of the grid and the handler for changes to each cell was to keep it simple and have a separate array of values per row and a separateonChange handler for each row. This is not a particularly effective way to structure this as there’s duplication in each of the nine handlers.

The State looked like this:

this.state =
        row1 : [],
        row2 : [],
        row3 : [],
        row4 : [],
        row5 : [],
        row6 : [],
        row7 : [],
        row8 : [],
        row9 : []

And each of the handlers looked like this, one handler per row, so handleChangeRow1() through  handleChangeRow9():

handleChangeRow1(index, event){
    console.log("row 1 update: " + event.target.value);
    var updatedRow = [...this.state.row1];
    updatedRow[index] = event.target.value
    this.setState( { row1 : updatedRow } );

This approach needed nine versions of the function above, each one specifically handling updates to the state for a single row. We’ll come back to improve a bit this later.

The interesting thing to notice, at this point, is that to update an array in a React state, you need to clone a copy of the array, and then update the copy. I used the spread operator ‘…’ to clone the array.

Each row in the grid I rendered separately like this (so this approach needed nine of these blocks):

        this.state.row1.map( (cell, index) => (
            <CellComponent key={index} value={this.state.row1[index]}
                           onChange={this.handleChangeRow1.bind(this, index)}/>

This was my first working version of the app, at least at the point where I could track the State of the grid as a user entered or changed values in the 9×9 grid. Next steps were to improve the approach.

Iteration 2: Using an Array of Arrays for the State

The first improvement was to improve the State arrays, moving to an array of arrays. This is easily set up like this:

this.state =
        grid: []

for (var row = 0; row < 9; row++) {
    this.state.grid[row] = [];

Iteration 3: One onChange Handler for All Rows

Instead of a handler per row, I parameterized the onChange handler to reuse for all rows. This is what I ended up with:

handleGridChange(row, colIndex, event) {
    console.log("row [" + row + "] col [" + colIndex + "] : " + event.target.value);
    var updatedGrid = [...this.state.grid];
    updatedGrid[row][colIndex] = event.target.value;

    //call Action to send updated data to Store

Using .map() on each of the rows in State, I then rendered each row of the grid like this, passing the current row index and column index as params into handleGridChange():

        this.state.grid[0].map((cell, colIndex) => (
                <td key={"row0" + colIndex}>
                    <CellComponent value={this.state.grid[0][colIndex]}
                                   onChange={this.handleGridChange.bind(this, 0, colIndex)}/>

I’m sure there’s a way to use a nested .map() of the results of a .map() or some other clever approach to render the whole grid in a single go, but rendering each of the individual rows is an OK approach with me, since there are only nine rows. If the number of rows was much more than nine, then I’d spend some time working on a better approach, but I’m OK with this for now.

Flux Action and Store

The Action to call the Lambda, and maintaining the state of the responses in the Store was pretty simple. You can check out the source here if you’re interested.

CSS Styling for the Grid

One last thing to do was to style the grid so it looks like a usual Sudoku grid, with vertical and horizontal lines at 3 and 6, to divide the grid in 3×3 of the 3×3 squares. This took some reading to find out how to easily implement this, but it turns out that CSS nth-child() psuedoclass handles this perfectly. I covered this in this post here.

Take a Look at the App

I might move this to a more permanent home later, but if you want to check out the app, you can take a look here.

cloud ,sudoku ,aws lambda ,react ,javascript ,aws ,tutorial ,front-end

Published at DZone with permission of Kevin Hooke , DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}