我尝试在
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);
};
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);