Example of using the redux-devtools Google extension plug-in

Table of Contents

1. store.ts

2. reducer.ts

3. ReduxProvider.tsx

4. mapStateToProps.ts

5. mapDispatchToProps.ts

6. Todo component (outermost package ReduxProvider

7. Subcomponents involved in the Todo component

1) TodoInput.tsx

2) TodoList.tsx

3) TodoItem.tsx

8. App components use Todo components


1. store.ts

Reference website: GitHub – zalmoxisus/redux-devtools-extension: Redux DevTools extension.

Download the Google extension plug-in address: react-redux-devtools: react-devtools-v3react-devtools-v4redux-devtools

import { applyMiddleware, combineReducers, legacy_createStore as createStore } from 'redux';
import { composeWithDevTools } from "redux-devtools-extension";
import thunk from 'redux-thunk';
import { todos, visibilityFilter } from './reduer';

// Use redux-devtools
const composeEnhancers = composeWithDevTools({
    // options like actionSanitizer, stateSanitizer
  });
  //Use redux-thunk middleware
  const enhancer = composeEnhancers(applyMiddleware(thunk));
export default createStore(combineReducers({ todos, visibilityFilter }), enhancer);

2. reducer.ts

export const visibilityFilter = (state = 'SHOW_ALL', action) => {
    switch (action.type) {
      //Set display type (all, completed, unfinished)
      case 'SET_VISIBILITY_FILTER':
        return action.filter
  
      //The default is SHOW_ALL
      default:
        return state
    }
  }

  //Add list data and change array data
  // Split the business logic into a separate file to facilitate status management
export interface StateProps {
    id: number;
    text: string;
    isFinished: boolean;
  }
  export interface ActionProps {
    type: string;
    [key: string]: any;
  }
export const todos = (state: StateProps[] | [], action: ActionProps) => {
    console.log(state, action);
    switch (action.type) {
      case "ADD":
        return [...state, action.todo];
      case "CHANGESTATUS":
        return state.map((item) => {
          if (item.id === action.id) {
            return Object.assign({}, item, { isFinished: !item.isFinished });
          }
          return item;
        });
      default:
        return state || [];
    }
  };

3. ReduxProvider.tsx

import React from "react";
import { Provider } from "react-redux";
import store from './store';

const ReduxProvider = (props) => {
  return <Provider store={store}>{props.children}</Provider>;
};

export default ReduxProvider

4. mapStateToProps.ts

// Different types of todo lists
const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case "SHOW_ALL": // Show all
      return todos;
    case "SHOW_FINISHED":
      return todos.filter((t) => t.isFinished);
    case "SHOW_NOT_FINISH":
      return todos.filter((t) => !t.isFinished);
    default:
      return todos;
  }
};

const mapStateToProps = (state) => {
  return {
    // Filter data based on completion status
    todoList: getVisibleTodos(state.todos, state.visibilityFilter),
  };
};

export default mapStateToProps;

5. mapDispatchToProps.ts

import { StateProps } from "./reduer";

const mapDispatchToProps = (dispatch) => {
    const changeTodo = (id: number) => {
      dispatch({ type: "CHANGESTATUS", id });
    };
    // add todo
    const addTodo = (todo: StateProps) => {
      dispatch({ type: "ADD", todo });
    };
  
    // show completed
    const showFinished = () => {
      dispatch({ type: "SET_VISIBILITY_FILTER", filter: 'SHOW_FINISHED' });
    }
    //Show unfinished
    const showNotFinish = () => {
      dispatch({ type: "SET_VISIBILITY_FILTER", filter: 'SHOW_NOT_FINISH' });
    }
    // Show all completed
    const showAll = () => {
      dispatch({ type: "SET_VISIBILITY_FILTER", filter: 'SHOW_ALL' });
    }
  
  
    return {
      addTodo,
      //Switch completion status
      changeTodo,
      showFinished,
      showNotFinish,
      showAll,
    };
  };

  export default mapDispatchToProps

6. Todo component (outermost package ReduxProvider

import React from "react";
import ReduxProvider from "./ReduxProvider";
import { TodoInput } from "./TodoInput";
import { TodoList } from "./TodoList";

// parent component
export const Todo = () => {
    return (
        <ReduxProvider>
            <TodoInput />
            <TodoList />
        </ReduxProvider>
    )
}

7. Subcomponents involved in Todo component

1) TodoInput.tsx

import React from "react";
import { useState } from "react";
import mapStateToProps from "./mapStateToProps";
import mapDispatchToProps from "./mapDispatchToProps";
import { connect } from "react-redux";

// Subassembly
const TodoInput0 = (props) => {
  const [text, setText] = useState("");
  const { addTodo, showAll, showFinished, showNotFinish } = props;
  const handleChangeText = (e: React.ChangeEvent) => {
    setText((e.target as HTMLInputElement).value);
  };
  const handleAddTodo = () => {
    if (!text) return;
    addTodo({
      id: new Date().getTime(),
      text: text,
      isFinished: false,
    });
    setText("");
  };
  return (
    <div className="todo-input">
      <input
        type="text"
        placeholder="Please enter to-do items"
        onChange={handleChangeText}
        value={text}
      />
      <button style={<!-- -->{ marginLeft: "10px" }} onClick={handleAddTodo}>
         + add
      </button>
      <button style={<!-- -->{ marginLeft: "10px" }} onClick={showAll}>
        show all
      </button>
      <button style={<!-- -->{ marginLeft: "10px" }} onClick={showFinished}>
        show finished
      </button>
      <button style={<!-- -->{ marginLeft: "10px" }} onClick={showNotFinish}>
        show not finish
      </button>
    </div>
  );
};

const TodoInput = connect(mapStateToProps, mapDispatchToProps)(TodoInput0);
export { TodoInput };

2) TodoList.tsx

import React from "react";
import { TodoItem } from "./TodoItem";
import _ from "lodash";
import { connect } from "react-redux";
import mapStateToProps from "./mapStateToProps";
import mapDispatchToProps from "./mapDispatchToProps";

const TodoList0 = (props) => {
  const { todoList } = props;

  return (
    <div className="todo-list">
      {_.map(todoList, (item) => (
        <TodoItem key={_.get(item, "id")} todo={item || {}} />
      ))}
    </div>
  );
};

const TodoList = connect(mapStateToProps, mapDispatchToProps)(TodoList0);
export { TodoList };

3) TodoItem.tsx

import React from "react";
import _ from "lodash";
import { connect } from "react-redux";
import mapStateToProps from "./mapStateToProps";
import mapDispatchToProps from "./mapDispatchToProps";

// grandson component
const TodoItem0 = (props) => {
  const { todo, changeTodo } = props;
  //Change event status
  const handleChange = () => {
    changeTodo(_.get(todo, "id"));
  };
  return (
    <div className="todo-item">
      <input
        type="checkbox"
        checked={todo.isFinished}
        onChange={handleChange}
      />
      <span
        style={<!-- -->{ textDecoration: todo.isFinished ? "line-through" : "none" }}
      >
        {todo.text}
      </span>
    </div>
  );
};
const TodoItem = connect(mapStateToProps, mapDispatchToProps)(TodoItem0);
export { TodoItem };

8. App component uses Todo component

import React from "react";
import { Todo } from "./reduxConnectProvider/Todo";

const App: React.FC = () => {
  return (
    <>
      <Todo />
    </>
  );
};

export default App;

Effect diagram