Family history, React and TypeScript

Let’s start a new app to organize family history using ReactJS and TypeScript.

Why am I doing this?

Today I was fiddling with some family history records and wondered, “Why don’t I write an app to help me organize this?”

I started to write it using just JavaScript, then thought, “I should write it in TypeScript so I’ll better understand it.”

Then as I wrote in TypeScript, I realized that rendering data to the DOM was a bit tedious, so I decided to use React JS as well. This way I’ll learn two tools in order to use them.

Introducing my sixth great-grandfather

Henry Michael Whittenberg is one of my sixth great-grandfathers, which I think means he goes back seven generations. Anyway, his data is what I’m starting with:

export interface IPerson {
  name: string;
  gender: string;
  birth: Date;
  death: Date;
}

const person: Person = {
  name: "Henry Michael Whittenberg”,
  gender: "Male”,
  birth: new Date("1710-01-01”),
  death: new Date("1767-01-19"),
};

So I have an interface called IPerson, where I have a basic structure for each person in my family history. Of course, there’s going to be some issues I’ll likely run into, such as if there’s a person where I don’t know the birthdate or some other fact. But I can revise that later. For today, I’m starting with someone I have some established facts about (although I question the accuracy of his birthdate).

Rendering the app

The app is fairly simple using React:

function App() {
  return (
    <main className="App”>
      <Person person={person} />
    </main>
  );
}

This renders a Person component, using person as the props.

const Person = (props: { person: IPerson }) => {
  const { person } = props;
    return (
      <dl>
        {Object.entries(person).map((fact) => (
          <Fact fact={fact} key={fact[0].toString()} />
        ))}
      </dl>
    );
};

For now, the Person component renders each of the facts using the Fact component. BTW, the component names are why I prefixed the interfaces with an I (e.g. IPerson, IFact, etc.)

Finally there’s the Fact component:

interface IFact {
  string: string | Date;
}

const Fact = (props: { fact: IFact[] }) => {
  const [key, value] = props.fact;
    return (
      <>
        <dt>{key}</dt>
        {value instanceof Date && <dd>{value.toLocaleDateString()}</dd>}
        {typeof value === "string" && <dd>{value}</dd>}
      </>
    );
};

The main reason I created a Fact component was to handle rendering the dates. In theory, I could use the .toLocaleString() method on almost any data type, but I wanted to be able to customize the way dates appear.