Search code examples
javascriptreactjstypescriptreact-hooksreact-usememo

React Typescript: How do I useMemo for a checkbox value?


I'm currently working on a to do list project using React and Typescript. Right now I am able to add a new to do item using a form and delete each to do item. Each to do item has a checkbox with a boolean value. What I would like to do is filter each to do item as "Done" when I click on the checkbox.

I have a Done (const DoneTasks) button on my page. Once it is clicked a copy of my App appears. Within the html components I want all my checked to do items to be stored on this page and filter out of the default App page.

I believe I have to useMemo for checked value, but I am not sure where to use it?

CODE SANDBOX: https://codesandbox.io/s/to-do-list-mkr29l

App.tsx

To Do Item Interface

interface ToDo {
  title: string;
  priority: 1 | 2;
  description: string;
  checked: true | false;
}

To Do Item function with checkbox prop

function ToDoItem(props: {
onCheckBoxCheck: any;}) 

{const checkBoxCheck = (event: any) => {
const checkBox = event.currentTarget.checked;
const newCheckBoxValue = checkBox;
console.log(checkBox);
props.onCheckBoxCheck(newCheckBoxValue);
};

  return (
    <div
      className="to-do-item"
      data-priority={props.toDo.priority}
      id="to-do-item">
      <div className="checkbox-title-container">
        <div className="check-title-div">
          <div>
            <input
              type="checkbox"
              id="checkbox"
              onChange={checkBoxCheck}
              checked={props.toDo.checked}
            />
          </div>
    </div>
  );
}

const initialTodosString = localStorage.getItem("toDoList");

const initialTodos = initialTodosString
  ? JSON.parse(initialTodosString)
  : [myToDo1, myToDo2];

App function with hooks, I think I should add useMemo in here?

function App(): JSX.Element {
  const [toDos, setToDos] = useState<ToDo[]>(initialTodos);
  const [addingToDo, setAddingToDo] = useState(false);
  const [showingDoneTasks, setShowDoneTasks] = useState(false);


  // Do I add useMemo here for checked value?


  useEffect(
    function () {
      localStorage.setItem("toDoList", JSON.stringify(toDos));
    },
    [toDos]
  );

showDone function

function showDone()
{setShowDoneTasks(true)}

//Done tasks function that returns html elements (I have included buttons in here)

const DoneTasks = () => (
        </div>
        <div className="status-container">
          <button className="activeButton">Active</button>
          <button className="doneButton" onClick={showDone}>Done
          </button>
        </div>
         </div>    
 );

if(showingDoneTasks){
  return <DoneTasks  />
};

App components (I kept buttons with To Do items and checkbox function below)

  return (
    <div className="App">
        <div className="status-container">
          <button className="activeButton">Active</button>
          <button className="doneButton" onClick={showDone}>Done
          </button>
        </div>
      </div>
    
      {toDos.map((toDoItem: ToDo) => (
        <ToDoItem
          onDeleteToDo={function () {
            const updatedToDos = toDos.filter((x) => x !== toDoItem);
            setToDos(updatedToDos);
            
          }}

          onCheckBoxCheck={function(checked: true | false) {
            const updatedToDos = toDos.map((x) =>
            x === toDoItem ? ({ ...x, checked } as any) : x,
          );
          setToDos(updatedToDos);}}

Solution

  • It's hard to read the code above, but you created multiple states/components to track down the filtered todos.

    Regarding your question about memos, you're right; that's where you need to add the memo since it's the parent component that "holds" your todos state.

    But, I would like to add some points to your implementation and make it more readable and easy to manage. Others may have different opinions, but I want to share my thoughts.

    Process:

    1. Create a "todos" state that manages the display of the Todo items. You can filter the display based on statuses like "done" or "not done."

      • With this implementation, you only have a single state to manage, and it's more predictable where to debug if the display is wrong
    2. Create a useRef that holds the initial state of the todos. This will be used to display if no status filter is made. This also helps prevent the component from being re-render when modified. Of course, you can use the useEffect when the .ref as a dependency when you want to save the updated the todos value.

    Please let me know if it still needs to be clarified. I'd be happy to help.

    Take note:

    • You don't have to use useMemo until you notice that you need to. useMemo is used for expensive computation. Still, it's not expensive in your case. useMemo also has some performance issues. So, use this with caution.

    Reference: https://kentcdodds.com/blog/usememo-and-usecallback