如何从我编写的自定义表单 child 组件修改 parent 组件的状态。这也可能影响 parent 的其他 children
How to modify state of a parent component from a child component which is a custom form I wrote. This might also effect other children of the parent
我写了一个名为 SingleFilterContainer
的自定义表单组件
在名为 FiltersContainer
的 parent 组件中,我初始化了一个状态 filters
,它最初有一个单一过滤器的数组和相应的 setFilters
函数来修改数组的过滤器。并且还有一个添加过滤器的按钮。在渲染函数中,我使用 filters.map
多次渲染 SingleFilterContainer
组件。到目前为止,这是有效的。但我想添加一个删除过滤器按钮。我把它放在 SingleFilterContainer
里面。当我单击它时,它应该更新 parent 组件中的状态 filters
并删除第 ith 个过滤器并正常呈现其余过滤器。或者重新渲染整个滤镜图。
我是 React 和 Hooks 的新手,我觉得我错过了什么。我这三天都在搞,有点迷路了。
这里是沙盒https://codesandbox.io/s/editing-filters-j2qrp
我觉得我处理状态的方式完全错误。也许我应该使用 redux?但我希望 SingleFilterContainer
像一种短暂的形式。或者删除过滤器按钮应该在 parent 组件内吗?并使用地图重复它?
这是我的 fork。
以下是我的修改。
function handleDeleteFilter(i) {
setFilters(filters => filters.filter((e, index) => index !== i));
}
重要提示:
- 理想情况下,您需要为数组中的每个项目分配一个
id
属性,而不是按索引进行比较。
- 不要直接改变状态。
.splice
直接改变状态。学习使用 .map
、.filter
& .reduce
数组函数
TL;DR Fixed fork
您的代码中的问题是您在渲染 onClick={handleDeleteFilter(i)}
上调用函数 onClick
需要对函数的引用,但是如果您希望此代码起作用,那么您所使用的方法从 parent 传递到 child 也需要 return 一个函数。
那么你的 handleDeleteFilter
将如下所示:
function handleDeleteFilter(i) {
return function() {
filters.splice(i, i + 1);
setFilters(filters => filters);
}
}
此外,在您的情况下,您不需要将 i + 1
作为第二个参数传递给 splice
,因为第二个参数是要删除的项目数量。在你的情况下,这只是 1。Docs
您将 i
传递给第一个函数,第二个函数会因关闭而看到它。
然后是删除一个元素。
改变状态是不好的做法,所以你可以有一个带有状态副本的局部变量,你可以操纵它然后更新状态。这样你就可以使用你想要的任何东西,但是在局部变量上。
所以你更新后的 handleDeleteFilter
看起来像
function handleDeleteFilter(i) {
return function() {
const clone = [...filters]
clone.splice(i, 1);
setFilters(clone);
}
}
或 .filter
function handleDeleteFilter(i) {
return function() {
const clone = filters.filter((item, index) => index !== i)
setFilters(clone);
}
}
这样您就不需要新变量,因为 .filter
return 是一个新数组。 Docs
我写了一个名为 SingleFilterContainer
在名为 FiltersContainer
的 parent 组件中,我初始化了一个状态 filters
,它最初有一个单一过滤器的数组和相应的 setFilters
函数来修改数组的过滤器。并且还有一个添加过滤器的按钮。在渲染函数中,我使用 filters.map
多次渲染 SingleFilterContainer
组件。到目前为止,这是有效的。但我想添加一个删除过滤器按钮。我把它放在 SingleFilterContainer
里面。当我单击它时,它应该更新 parent 组件中的状态 filters
并删除第 ith 个过滤器并正常呈现其余过滤器。或者重新渲染整个滤镜图。
我是 React 和 Hooks 的新手,我觉得我错过了什么。我这三天都在搞,有点迷路了。
这里是沙盒https://codesandbox.io/s/editing-filters-j2qrp
我觉得我处理状态的方式完全错误。也许我应该使用 redux?但我希望 SingleFilterContainer
像一种短暂的形式。或者删除过滤器按钮应该在 parent 组件内吗?并使用地图重复它?
这是我的 fork。
以下是我的修改。
function handleDeleteFilter(i) {
setFilters(filters => filters.filter((e, index) => index !== i));
}
重要提示:
- 理想情况下,您需要为数组中的每个项目分配一个
id
属性,而不是按索引进行比较。 - 不要直接改变状态。
.splice
直接改变状态。学习使用.map
、.filter
&.reduce
数组函数
TL;DR Fixed fork
您的代码中的问题是您在渲染 onClick={handleDeleteFilter(i)}
上调用函数 onClick
需要对函数的引用,但是如果您希望此代码起作用,那么您所使用的方法从 parent 传递到 child 也需要 return 一个函数。
那么你的 handleDeleteFilter
将如下所示:
function handleDeleteFilter(i) {
return function() {
filters.splice(i, i + 1);
setFilters(filters => filters);
}
}
此外,在您的情况下,您不需要将 i + 1
作为第二个参数传递给 splice
,因为第二个参数是要删除的项目数量。在你的情况下,这只是 1。Docs
您将 i
传递给第一个函数,第二个函数会因关闭而看到它。
然后是删除一个元素。
改变状态是不好的做法,所以你可以有一个带有状态副本的局部变量,你可以操纵它然后更新状态。这样你就可以使用你想要的任何东西,但是在局部变量上。
所以你更新后的 handleDeleteFilter
看起来像
function handleDeleteFilter(i) {
return function() {
const clone = [...filters]
clone.splice(i, 1);
setFilters(clone);
}
}
或 .filter
function handleDeleteFilter(i) {
return function() {
const clone = filters.filter((item, index) => index !== i)
setFilters(clone);
}
}
这样您就不需要新变量,因为 .filter
return 是一个新数组。 Docs