简体   繁体   English

React - 当道具将 function 导出到子组件时,备忘录不起作用

[英]React - Memo not working when a function is exported to child component by props

I have a problem in React.我在 React 中遇到问题。 The problem in question is about the use of the memo, basically, I have a list generator application, and I use the memo in the list item(child) component, so far so good, working.有问题的问题是关于备忘录的使用,基本上,我有一个列表生成器应用程序,我在列表项(子)组件中使用备忘录,到目前为止一切顺利,工作正常。 The problem is that when I export functions through props, that is, functions from the parent component to the child component, the memo doesn't work.问题是当我通过props导出函数,即父组件到子组件的函数时,memo不起作用。

The goal is for the memo, to do its default purpose with the list items, and not render everything in the virtual dom.备忘录的目标是对列表项执行其默认目的,而不是在虚拟 dom 中呈现所有内容。

  import React from 'react'
  import {memo} from 'react'
  import "./Task.css"
  import  junk from "../../img/junk.png"
  import  star from "../../img/star.png"
  import  starFull from "../../img/star-full.png"
  import  verifyFull from "../../img/verify-full.png"
  import  verify from "../../img/verify.png"

  const Task = (props) => {
    return (
      <div className='task'>
          <div className='task_title'>
            <h2>{props.title}</h2>
            <div className='task_settings' >
              <button onClick={props.handleFavorite}><img src= {props.favorite?starFull:star} alt="" /></button>
              <button onClick={props.handleComplete}><img src= {props.complete?verifyFull:verify} alt="" /></button>
              <button onClick={props.handleDelete} ><img src={junk} alt="" /></button>            
            </div>
          </div>
          <div className='task_description'>
            {props.description}
          </div>
          <div>
            {props.date}
          </div>
      </div>
    )

/------------------------------------------ /----------------------------------------

import './TaskManeger.css'
import {Task} from "../../components";
import React, {useState,useEffect,memo} from 'react'

const TaskManeger = () => {

  const [formValues,setValues] = useState({
    title:"",
    description:"",
    date:""}
  )

  const [list,setList] = useState([]
  )

  function maskDate(value) {
    return value
      .replace(/\D/g, "")
      .replace(/(\d{2})(\d)/, "$1/$2")
      .replace(/(\d{2})(\d)/, "$1/$2")
      .replace(/(\d{4})(\d)/, "$1");
  };

  function handleInput(e) {
    const {name,value} = e.target
    setValues(name==="date"?{...formValues,[name]:maskDate(value)}:{...formValues,[name]:value})    
  }//set values in input

  function handleSubmit(e) {
    e.preventDefault()
    const formData = new FormData(e.target)
    const data = Object.fromEntries(formData)
    addTask(data)
  }//creat object with values for input

  function handleAddFavorite(id) {
    setList(list.map( itemList => {return itemList.id === id ?  { ...itemList, favorite: !itemList.favorite } : itemList}))
  }

  function handleAddComplete(id) {
    setList(list.map( itemList => {return itemList.id === id ?  { ...itemList, complete: !itemList.complete } : itemList}))
  }

  function deleteTask(item) {
    setList(list.filter(i=> i.id !== item.id))
  }

  function addTask(e) {
    setList([...list,{title:e.title, description:e.description, date:e.date, id:list.length,favorite:false,complete:false}])
  }//creat object in list 
  
  useEffect(() => {
    setList([...list,
    {title:"Siga As Instrtuções ", description:"Abaixo nos temos varias tarefas, e nos iremos passar por um tutorial em cada uma delas, siga e conforme for completando-as, conclua no icone de visto a acima.", date:"", id:0,favorite:false},
    {title:"Crie Suas Tarefas", description:"Ao lado, podemos ver um formulario, onde você pode preencher as informações para você mesmo criar suas tarefas.", date:"", id:1,favorite:false},
    {title:"Favorite Suas Tarefas", description:"Você pode favoritar as tarefas atravez da estrela que esta acima, a direita do seu titulo.", date:"", id:2,favorite:false},
    {title:"Apague Suas Tarefas", description:"Você pode apagar as tarefas atravez da lixeira que esta acima, a direita do seu titulo.", date:"", id:3,favorite:false},
    {title:"Filtre", description:"Alem disso tudo que ja falamos nas tarefas anteriores, você pode filtrar suas tarefas, caso queira ver apenas as completadas, ou as que ainda faltam ser completadas, as favoritas, ou todas.", date:"", id:4,favorite:false}])
  }, [])
  
  return (
    <div className="tasks">
      <div className="tasks_container">
        <div className="task_generator">
          <form onSubmit={handleSubmit}>
            <input placeholder='Titulo' name='title' type="text" onChange={handleInput} value={formValues.title}/>
            <input placeholder='Descrição'  name='description' type="text" onChange={handleInput} value={formValues.description}    />
            <input placeholder='Data' name='date' onChange={handleInput} value={formValues.date} />
            <button type="submit">Criar</button>
          </form>  
        </div>
        <div className="task_list">
            <div className='task_filter'>
              <div>Filtrar ▼</div>
              <p>Todos</p>
              <p>Completados</p>
              <p>Favoritos</p>
            </div>
            {list.map( itemList =>(
                <Task 
                  key={itemList.id}
                  title={itemList.title}
                  description={itemList.description}
                  date={itemList.date}
                  handleDelete={()=>deleteTask(itemList)}
                  handleFavorite={()=>handleAddFavorite(itemList.id)}
                  handleComplete={()=>handleAddComplete(itemList.id)}
                  id={itemList.id}
                  favorite={itemList.favorite}
                  complete={itemList.complete}
              />
            ))}          
        </div>        
      </div>
    </div>
  ) 
}

export  default TaskManeger

The memo is not working because the functions you are passing in are not referentially stable memo不起作用,因为您传入的函数引用不稳定

handleDelete={()=>deleteTask(itemList)}
handleFavorite={()=>handleAddFavorite(itemList.id)}
handleComplete={()=>handleAddComplete(itemList.id)}

You create three new functions on every render and pass them as prop.您在每个渲染器上创建三个新函数并将它们作为 prop 传递。 memo tests for referential equality ( === ) of each prop, but (() => x) !== (() => x) . memo测试每个道具的引用相等性 ( === ),但是(() => x) !== (() => x)

You could pass in the functions like so:您可以像这样传递函数:

handleDelete={deleteTask}
handleFavorite={handleAddFavorite}
handleComplete={handleAddComplete}

and make the child component pass the argument instead.并让子组件传递参数。

You would also need to use useCallback for those functions to get stability.您还需要对这些函数使用useCallback以获得稳定性。

const deleteTask = useCallback((item) => {
    setList(list => list.filter(i => i.id !== item.id))
}, [setList])

// repeat pattern for all three functions

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM