typescript - use map

  • Commit 
https://github.com/shooeugenesea/study-js/commit/2d22117a7b36ea1225b960892995e409bbc5e64f
    https://github.com/shooeugenesea/study-js/commit/30cb24cd3a5dc57dde750fa6e90a04b88dba8084
    • Declare class with map
    • export class TestMap {
          private map: Map<string, string> = new Map();

          put(key:string, val:string): void {
              if (key) {
                  this.map.set(key, val);
              }
          }

          get(key:string): string | undefined {
              if (key) {
                  return this.map.get(key)
              }
          }

          count(): number {
              return this.map.size;
          }

          clearByKeyPrefix(prefix: string) {
              this.map.forEach((v: string, k:string, m:Map<string,string>) => {
                  if (k.startsWith(prefix)) {
                      m.delete(k);
                  }
              })
          }
      }
    • Put and get then print
    • const testMap = new TestMap();
      testMap.put("ka", "vka");
      testMap.put("kb", "vka");
      testMap.put("kc", "vka");
      testMap.put("kd", "vka");
      testMap.put("ke", "vka");
      testMap.put("aa", "vaa");
      console.log(testMap);
      console.log(testMap.count()); // 6
      testMap.clearByKeyPrefix("k"); // print 6 entries
      console.log(testMap.get("aa")); // print vaa


    redux - typescript - change index.js to support typescript

    Git Commit

    • Install typescript
    npm install --save-dev typescript
    • New Helloworld.ts
    export class Helloworld {
        public name: String;

        public constructor(name:String) {
            this.name = name;
        }

        public greeting(): void {
            console.log(`Helloworld! ${this.name}`);
        }
    }
    • New TodoItem.ts
    export class TodoItem {
        public constructor(public id:String, public task:String, public done:boolean) {
        }

        public printDetail():void {
            console.log(`${this.id} / ${this.task} / ${this.done}`);
        }
    }
    • New TodoItemCollection.ts
    import {TodoItem} from "./TodoItem";

    export class TodoItemCollection {
        constructor(public name:String, public todoItems: TodoItem[]) {
        }

        public addItem(item: TodoItem): number {
            return this.todoItems.push(item);
        }

        public getItemById(id:String): TodoItem | undefined {
            return this.todoItems.find(item => item.id === id);
        }

        public markDone(id:String) {
            const item = this.getItemById(id)
            if (item) {
                item.done = true
            }
        }
    }
    • Rename index.js to index.tsx
    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    import {createStore, applyMiddleware} from 'redux'
    import { Provider } from 'react-redux'
    import reducers from './reducers'
    import thunk from "redux-thunk";
    import {Helloworld} from './ts/Helloworld'
    import {TodoItemCollection} from "./ts/TodoItemCollection";
    import {TodoItem} from "./ts/TodoItem";

    const store = createStore(reducers, applyMiddleware(thunk));

    ReactDOM.render(
          <Provider store={store} >
              <App />
          </Provider>,
      document.getElementById('root')
    );

    const h = new Helloworld("KKK");
    h.greeting();

    const todos = new TodoItemCollection("name1", [
        new TodoItem("id1", "task1", false),
        new TodoItem("id2", "task2", false),
        new TodoItem("id3", "task3", false),
    ]);
    todos.addItem(new TodoItem("id4", "task4", false));
    console.log(todos);
    todos.markDone("id2");
    console.log(todos.getItemById("id2"));
    • Check typescript works


    redux - redux thunk - prevent duplicated request


    =================== Prepare ========================
    • whenever we dispatch a function, redux pick it up and invoke it
    export const fetchPostsAndUsers = () => async dispatch => {
        await // need await because invoking an async function and we want to wait until it's done
            dispatch( // dispatch an "async dispatch..." function, so invoke it directly
                fetchPosts() // call export const fetchPosts = ()
                             // and return "async dispatch => { ... }"
            )
    }

    export const fetchPosts = () => async dispatch => {
        const response = await jsonPlaceholder.get('/posts')

        dispatch({type:'FETCH_POSTS', payload: response.data})
    }
    Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters.
    If a property name is provided for iteratee the created _.property style callback returns the property value of the given element.
    Creates a duplicate-free version of an array, using SameValueZero for equality comparisons, in which only the first occurrence of each element is kept. The order of result values is determined by the order they occur in the array.

    ===================== Need to change =================
    • Remove memoize function
    export const fetchUser = (userId) => async dispatch => {
        const response = await jsonPlaceholder.get(`/users/${userId}`)

        dispatch({type:'FETCH_USER', payload: response.data})
    }
    • Create fetchPostsAndUsers function
    export const fetchPostsAndUsers = () => async (dispatch, getState) => {
        await dispatch (fetchPosts());
        const userIds = _.uniq(_.map(getState().fetchPosts, 'userId'))
        userIds.forEach(id => dispatch(fetchUser(id)))
    }
    • Fetch posts and users from PttPosts.js
    import React, {Component} from "react";
    import {connect} from 'react-redux'
    import {fetchPostsAndUsers, selectPttPost} from "../actions";
    import UserHeader from "./UserHeader";

    class PttPosts extends Component {
        componentDidMount() {
            this.props.fetchPostsAndUsers()
        }

        renderList() {
            if (this.props.postList) {
                return this.props.postList.map((post) => {
                    return <div key={post.id}>
                        <div key={post.id}><a onClick={() => this.props.selectPttPost(post)}>Title:{post.title}</a></div>
                        <UserHeader userId={post.userId} />
                    </div>
                });
            } else {
                return 'Loading...'
            }
        };

        render() {
            return <div>{this.renderList()}</div>
        }
    }

    const mapStateToProps = (state) => {
        return {postList: state.fetchPosts};
    }

    export default connect(mapStateToProps, { fetchPostsAndUsers, selectPttPost })(PttPosts)
    • Don't need fetchUsers from UserHeader.js
    import React, {Component} from "react";
    import {connect} from 'react-redux'
    import {fetchUser} from "../actions";

    class UserHeader extends Component {

        componentDidMount() {
            this.props.fetchUser(this.props.userId)
        }

        render() {
            return <div>Author: {this.props.user?.name}</div>
        }
    }

    const mapStateToProps = (state, props) => {
        return {user: state.users?.find(user => user.id === props.userId)}
    }

    export default connect(mapStateToProps, {fetchUser})(UserHeader)
    • Duplicated requests disappear


    Lessons Learned While Using Claude Code Skills

    Recently, I started experimenting with Claude Code Skills . I first saw this YouTube video: https://www.youtube.com/watch?v=CEvIs9y1uog ...