zoukankan      html  css  js  c++  java
  • [React] Preventing extra re-rendering with function component by using React.memo and useCallback

    Got the idea form this lesson. Not sure whether it is the ncessary, no othere better way to handle it.

    Have a TodoList component, every time types in NewTodo input fields, will trigger the re-rendering for all components.

    import React, { useState, useContext, useCallback } from "react";
    import NewTodo from "./NewTodo";
    import TodoItem from "./TodoItem5";
    import { Container, List } from "./Styled";
    import About from "./About";
    import { useTodosWithLocalStorage, useKeyDown } from "./hooks";
    import { useTitle as useDocumentTitle } from "react-use";
    import ThemeContext from "./ThemeContext";
    
    const incompleteTodoCount = todos =>
      todos.reduce((memo, todo) => (!todo.completed ? memo + 1 : memo), 0);
    
    export default function TodoList() {
      const [newTodo, updateNewTodo] = useState("");
      const [todos, dispatch] = useTodosWithLocalStorage([]);
      const inCompleteCount = incompleteTodoCount(todos);
      const title = inCompleteCount ? `Todos (${inCompleteCount})` : "Todos";
      useDocumentTitle(title);
      let [showAbout, setShowAbout] = useKeyDown(
        { "?": true, Escape: false },
        false
      );
      const handleNewSubmit = e => {
        e.preventDefault();
        dispatch({ type: "ADD_TODO", text: newTodo });
        updateNewTodo("");
      };
      const theme = useContext(ThemeContext);
    
      return (
        <Container todos={todos}>
          <NewTodo
            onSubmit={handleNewSubmit}
            value={newTodo}
            onChange={e => updateNewTodo(e.target.value)}
          />
          {!!todos.length && (
            <List theme={theme}>
              {todos.map(todo => (
                <TodoItem
                  key={todo.id}
                  todo={todo}
                  onChange={id => dispatch({ type: "TOGGLE_TODO", id })}
                  onDelete={id => dispatch({ type: "DELETE_TODO", id })}
                />
              ))}
            </List>
          )}
          <About isOpen={showAbout} onClose={() => setShowAbout(false)} />
        </Container>
      );
    }

    The way to solve the problem is

    1. For every callback:

    <TodoItem
        onChange={id => dispatch({ type: "TOGGLE_TODO", id })}
        onDelete={id => dispatch({ type: "DELETE_TODO", id })}
    />
    
    <About isOpen={showAbout} onClose={() => setShowAbout(false)} />

    We should replace with useCallback hooks:

      const handleChange = useCallback(
        id => dispatch({ type: "TOGGLE_TODO", id }),
        []
      );
      const handleDelete = useCallback(
        id => dispatch({ type: "DELETE_TODO", id }),
        []
      );
    
      const handleClose = userCallback(
        () => setShowAbout(false), []
      )
          {!!todos.length && (
            <List theme={theme}>
              {todos.map(todo => (
                <TodoItem
                  key={todo.id}
                  todo={todo}
                  onChange={handleChange}
                  onDelete={handleDelete}
                />
              ))}
            </List>
          )}
          <About isOpen={showAbout} onClose={handleClose} />

    This helps to reduce some extra re-rendering. 

    2. Using Reac.memo for function component:

    import React, { useContext } from "react";
    import Checkbox from "./Checkbox";
    import ThemeContext from "./ThemeContext";
    import { Button, Item } from "./Styled";
    
    const TodoItem = React.memo(({ todo, onChange, onDelete }) => {
      console.log("TodoItem5", { todo, onChange, onDelete });
      const theme = useContext(ThemeContext);
      return (
        <Item key={todo.id} theme={theme}>
          <Checkbox
            id={todo.id}
            label={todo.text}
            checked={todo.completed}
            onChange={onChange.bind(this, todo.id)}
          />
          <Button onClick={onDelete.bind(this, todo.id)} theme={theme}>
            x
          </Button>
        </Item>
      );
    });
    
    export default TodoItem;
    import React from "react";
    import styled from "react-emotion";
    
    import { Dialog } from "@reach/dialog";
    
    ...
    
    export default React.memo(function TodoItem({ isOpen, onClose }) {
      return (
        <Dialog isOpen={isOpen}>
          ...
        </Dialog>
      );
    });

    Assume that every times I should wrap function component with React.memo() and use useCallback whenever necessary.

  • 相关阅读:
    CSS3新特性
    CSS简述
    HTML5新属性
    Python学习笔记(十二)
    Python学习笔记(十一)
    Python学习笔记(十)
    Python学习笔记(九)
    Python学习笔记(八)
    Python学习笔记(七)
    Python学习笔记(六)
  • 原文地址:https://www.cnblogs.com/Answer1215/p/10432142.html
Copyright © 2011-2022 走看看