React.useCallback :它不会阻止连续重新渲染
React.useCallback : it doesn't prevent continuos re-rendering
我正在尝试在 React.useEffect
中使用 React.useCallback
函数以避免连续重新渲染。
我的 objective 是,一旦选择了排序选项,即使添加了新元素,也会保持列表排序。但是没有连续渲染。
这就是为什么我尝试使用 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: "Lucio_Hettinger@annie.ca",
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: "Karley_Dach@jasper.info",
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 运行s,您都会进入渲染循环,创建一个新的 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 函数,您正在改变状态。确保制作一个新阵列。所以而不是 this:1
newData = data;
newData.push(employee);
setData(newData);
这样做:
const newData = [...data];
newData.push(employee);
setData(newData);
我正在尝试在 React.useEffect
中使用 React.useCallback
函数以避免连续重新渲染。
我的 objective 是,一旦选择了排序选项,即使添加了新元素,也会保持列表排序。但是没有连续渲染。
这就是为什么我尝试使用 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: "Lucio_Hettinger@annie.ca",
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: "Karley_Dach@jasper.info",
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 运行s,您都会进入渲染循环,创建一个新的 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 函数,您正在改变状态。确保制作一个新阵列。所以而不是 this:1
newData = data;
newData.push(employee);
setData(newData);
这样做:
const newData = [...data];
newData.push(employee);
setData(newData);