interest calculator with React+Redux
Everything's on the front-end You're using HTM to interpret the JSX by putting the JSX through a template literal. It's quite an interesting option, but for a professional project, I think compiling the JSX beforehand in a build process would be a better choice:

It's very easy to make syntactical typos in the template literal, and you have to run the script in order to see them. If something gets conditionally rendered, you may not see problems with your syntax until the component gets rendered, which may be uncommon; the potential bugs will be significantly harder to encounter and fix. In contrast, if you put the JSX inside a JSX file, and use a syntax-aware IDE like VSCode, you'll be able to spot such mistakes on sight and fix them immediately.
Transpiling the script ahead of time also makes things much easier if you decide to make the project larger. For example, if you have component A and notice that something isn't working right with it, you could have a standalone A.jsx file that you could go to and debug. (In contrast, if you have, say, 200 or 400 or 1000 lines of code in a single file without a build process, it gets more difficult to navigate around than it should be)
Having standalone .js / .jsx files also allows for linting, which I consider to be absolutely essential to enforcing code style and quality, and which can turn difficult-to-debug runtime errors into trivially fixable compile-time errors.
It also allows you to transpile ES2020+ syntax down to ES2015 or ES5 or whatever you prefer, which can make code easier to read and write while remaining compatible with as many browsers as possible.

It's just an option to consider. If you're not happy at the amount of setup it requires, you can use boilerplate like create-react-app so that it's nearly ready to go out of the box.
Avoid let and reassignment When variable names are permitted to be reassigned, it can make code more difficult to understand at a glance, when you always have to keep in mind &quot;This variable was declared with let, so I need to be on the lookout for when it may be reassigned.&quot; (Linting rule: prefer-const). See this post on softwareengineering about the topic. There are a number of other places in the code where you're using let where const can be used instead.
In the reducer, rather than reassign store and then return it at the bottom of the switch, you can return it immediately. (You could also consider avoiding the switch here, since it requires a lot of unnecessary boilerplate).
// When an argument list requires multiple lines,
// I think it's easier to read to put each argument on a separate line like this:
function reducer(
    model={total: 0},
    action={type:'', payload: null}
) {
    switch(action.type){
        case 'TOTAL_COST':
            return { total: action.payload.total };
        default:
            return model;
    }
}

or, if the reducer won't be expanded in the future:
function reducer(
    model={total: 0},
    action={type:'', payload: null}
) {
    return action.type === 'TOTAL_COST'
        ? { total: action.payload.total };
        : model;
}

this binding and mount actions You do:
constructor(props){
    super(props);
    this.state = {
        principal: 1000,
        years: 7,
        rate: 0.025
    };
    this.submit = this.submit.bind(this);
    this.update = this.update.bind(this);
    this.submit(new CustomEvent('init'));
}

There are 2 improvements that can be made here: first, consider using class fields to define the methods instead of using .bind in the constructor, to be more concise and avoid boilerplate. Secondly, populating the component initially with this.submit(new CustomEvent('init'));, an event that is passed only so that calling e.preventDefault on it later doesn't throw is weird. How about using optional chaining in submit instead of passing a parameter?
class App extends React.Component{
    state = {
        principal: 1000,
        years: 7,
        rate: 0.025
    };
    constructor(props){
        super(props);
        this.submit();
    }
    submit = (e) =&gt; {
        e?.preventDefault();
        this.props.dispatch( actions.updateTotal(this.state) );
    }
    update = (e) =&gt; {

You could also consider using functional components instead; React recommends using them instead of class components for new code - they make code a bit easier to understand and maintain.
Update You have:
update(e){
    let { valueAsNumber, value, name } = e.target;
    const state = {...this.state};
    if(isNaN(valueAsNumber)){
        valueAsNumber = 0;
    }
    state[ name ] = valueAsNumber;
    this.props.dispatch( actions.updateTotal(state) );
    this.setState({[name]: valueAsNumber});
}

When using React, seeing something like
state[ name ] = valueAsNumber;

should look scary, because it looks very close to mutating state, and state should never be mutated in React - see here for lots of articles on the subject. While your current method works, it may well be worrying at a glance. Consider using a more functional approach, to construct the new state all at once, without mutation:
update = (e) =&gt; {
    const { valueAsNumber, value, name } = e.target
    const newState = {
      ...this.state,
      [name]: valueAsNumber || 0
    };
    this.props.dispatch( actions.updateTotal(newState) );
    this.setState(newState);
}