React.useCallback:它不会阻止连续重新渲染

问题描述 投票:0回答:1

我尝试在

React.useCallback
中使用
React.useEffect
函数以避免连续重新渲染。

我的目标是,一旦选择了排序选项,即使添加新元素也保持列表排序。但没有连续渲染。 这就是为什么我尝试使用

React.useCallback

但到目前为止我所做的并不能阻止连续重新渲染......

这些

React.useCallback
功能有什么问题吗?

 const memoizedIncrByName = React.useCallback(() => {
    let new_data = [...data].sort((a, b) => {
      if (b.name < a.name) return 1;
      if (b.name > a.name) return -1;
      return 0;
    });
    setData(new_data);
  }, [data]);

  const memoizedIncrByEmail = React.useCallback(() => {
    let new_data = [...data].sort((a, b) => {
      if (b.email < a.email) return 1;
      if (b.email > a.email) return -1;
      return 0;
    });
    setData(new_data);
  }, [data]);

  React.useEffect(() => {
    console.log("SelectedOption:", selectedSortingOption);
    if (selectedSortingOption !== null) {
      if (selectedSortingOption.value === "name") {
        memoizedIncrByName();
      } else if (selectedSortingOption.value === "email") {
        memoizedIncrByEmail();
      }
    }
  }, [memoizedIncrByName, memoizedIncrByEmail, selectedSortingOption]);



    <Select
          defaultValue={selectedSortingOption}
          onChange={SetSelectedSortingOption}
          options={sortingOptions}
        />

data
样品:

let new_users = [
  {
    id: 5,
    name: "Chelsey Dietrich",
    username: "Kamren",
    email: "[email protected]",
    address: {
      street: "Skiles Walks",
      suite: "Suite 351",
      city: "Roscoeview",
      zipcode: "33263",
      geo: {
        lat: "-31.8129",
        lng: "62.5342"
      }
    },
    phone: "(254)954-1289",
    website: "demarco.info",
    company: {
      name: "Keebler LLC",
      catchPhrase: "User-centric fault-tolerant solution",
      bs: "revolutionize end-to-end systems"
    }
  },
  {
    id: 6,
    name: "Mrs. Dennis Schulist",
    username: "Leopoldo_Corkery",
    email: "[email protected]",
    address: {
      street: "Norberto Crossing",
      suite: "Apt. 950",
      city: "South Christy",
      zipcode: "23505-1337",
      geo: {
        lat: "-71.4197",
        lng: "71.7478"
      }
    },
    phone: "1-477-935-8478 x6430",
    website: "ola.org",
    company: {
      name: "Considine-Lockman",
      catchPhrase: "Synchronised bottom-line interface",
      bs: "e-enable innovative applications"
    }
  },

更新1)

按照Nicholas Tower的明智建议,我尝试了这样的方法:

  const sortedData = React.useMemo(() => {
    if (selectedSortingOption !== null) {
      if (selectedSortingOption.value === "name") {
         return [...data].sort((a, b) => {
          if (b.name < a.name) return 1;
          if (b.name > a.name) return -1;
          return 0;
        });
      } else if (selectedSortingOption.value === "email") {
        return [...data].sort((a, b) => {
          if (b.email < a.email) return 1;
          if (b.email > a.email) return -1;
          return 0;
        })
      } else {
        return data;
      }
    } else {
      return data;
    }
  }, [data, selectedSortingOption]);

现在它不再连续重新渲染,但是,令人惊讶的是,当我在数据中添加新项目并更新

data
时,它不会重新渲染。为了让新数据出现,我必须更改
selectedSortingOption
。 所以,我想,还有其他问题需要解决

这是单击按钮时调用的函数

AddEmployee

const [newEmployee, setNewEmployee] = React.useState([]);

  const addSingleEmployee = () => {
    if (new_users.length === 0) {
      return;
    }
    let employee = new_users[0];

    let employeeArray = [];
    employeeArray.push(employee);
    setNewEmployee(employeeArray);

    new_users.shift();
    newData = data;
    newData.push(employee);
    setData(newData);
  };
reactjs react-hooks
1个回答
1
投票
 const memoizedIncrByName = React.useCallback(() => {
    let new_data = [...data].sort((a, b) => {
      if (b.name < a.name) return 1;
      if (b.name > a.name) return -1;
      return 0;
    });
    setData(new_data);
  }, [data]);

每次数据发生变化,记忆就会中断。但每次调用该函数时,都会更改数据,从而破坏了记忆。由于每次 memoizedIncrByName 或 memoizedIncrByEmail 更改时 useEffect 都会运行,因此您会进入一个循环,在该循环中进行渲染、创建新的 memoizedIncrByName、运行效果、调用 memoizedIncrByName,后者再次渲染并重复该过程。

如果您想保留 useEffect,我建议将函数移至效果内部,并使效果仅取决于排序选项:

React.useEffect(() => {
  const incrByName = () => {
    let new_data = [...data].sort((a, b) => {
      if (b.name < a.name) return 1;
      if (b.name > a.name) return -1;
      return 0;
    });
    setData(new_data);
  };
  const incrByEmail = () => {
    let new_data = [...data].sort((a, b) => {
      if (b.email < a.email) return 1;
      if (b.email > a.email) return -1;
      return 0;
    });
    setData(new_data);
  }

  if (selectedSortingOption !== null) {
      if (selectedSortingOption.value === "name") {
        incrByName();
      } else if (selectedSortingOption.value === "email") {
        incrByEmail();
      }
    }
}, [selectedSortingOption]);

但我实际上建议完全放弃 useEffect。当您使用 use Effect 方法时,每次想要更改排序时,您最终都必须渲染两次:一次是为了更新排序状态,然后是在 useEffect 更新数据状态时再次渲染。相反,您可以让排序列表成为渲染期间计算的值。为了提高性能,您可以将计算包装在 useMemo 中,以便在没有任何更改的情况下跳过计算:

const [data, setData] = useState(/* the full unsorted array */);
const [selectedSortingOption, setSelectedSortingOption] = useState(null);

const sortedData = useMemo(() => {
  if (selectedSortingOption.value === "name") {
     return [...data].sort((a, b) => {
      if (b.name < a.name) return 1;
      if (b.name > a.name) return -1;
      return 0;
    });
  } else if (selectedSortingOption.value === "email") {
    return [...data].sort((a, b) => {
      if (b.email < a.email) return 1;
      if (b.email > a.email) return -1;
      return 0;
    })
  } else {
    return data;
  } 
}, [data, selectedSortingOption]);

// Use sortedData below here

编辑:对于 addSingleEmployee 函数,您正在改变状态。确保创建一个新数组。所以代替这个:1

newData = data;
newData.push(employee);
setData(newData);

这样做:

const newData = [...data];
newData.push(employee);
setData(newData);
© www.soinside.com 2019 - 2024. All rights reserved.