我最近开始在react中使用钩子,我经常遇到这样的问题:我创建了第一个大状态,供我的所有组件使用,但为了简单起见,我的组件中的一些较小部分划分了这个状态,并创建了自己的状态。
例如
import React, { useState } from "react";
const initialFilters = {
name: "",
code: ""
};
function Filter({ value, setFilters }) {
const [tempValue, setTempValue] = useState(value);
return (
<input
value={tempValue}
onChange={e => setTempValue(e.target.value)}
onBlur={() => setFilters(tempValue)}
/>
);
}
function App() {
const [filters, setFilters] = useState(initialFilters);
const agents = [
{ name: "bob", code: "123" },
{ name: "burger", code: "3123" },
{ name: "sponge", code: "34" }
];
return (
<div>
<label>Name filter</label>
<Filter
value={filters.name}
setFilters={value =>
setFilters(filters => ({ ...filters, name: value }))
}
/>
<label>Code filter</label>
<Filter
value={filters.code}
setFilters={value =>
setFilters(filters => ({ ...filters, code: value }))
}
/>
<button onClick={() => setFilters(initialFilters)}>Reset filters</button>
<ul>
{agents
.filter(
agent =>
agent.name.includes(filters.name) &&
agent.code.includes(filters.code)
)
.map((agent, i) => (
<li key={i}>
name: {agent.name} - code: {agent.code}
</li>
))}
</ul>
</div>
);
}
export default App;
CodeSandox在这里可用
在本例中,过滤器工作正常,但当我们使用"重置"按钮时,它们的值不会被清空。
过滤器创建自己的状态以仅在模糊时调度新状态,并且仍然受到控制。我想我可以在这里使用ref,但我用这个例子来展示一个简单的状态依赖于另一个状态(因此依赖于道具(的情况。
我应该如何以惯用的React方式实现它?
您可以使用useEffect
挂钩。第一个参数是一个函数,第二个参数是依赖项数组。当依赖项更改值时,函数将再次执行。
import { useEffect } from 'react';
// ....code removed....
useEffect(() => {
setTempValue(value);
}, [value]);
// ....code removed....
带有更改的沙盒:https://codesandbox.io/s/kind-bogdan-ljugv
如您在文档中所读(https://reactjs.org/docs/hooks-state.html#declaring-a-state-variable(,则仅在第一次渲染时创建状态,然后它才等于初始值。您可以编写一个自定义挂钩useFilter
并公开您的过滤器重置:
const useFilter = (value, setFilters) => {
const [tempValue, setTempValue] = useState(value);
const resetFilter = () => setTempValue(value)
return {
resetFilter,
getInputProps: () => ({
onChange: e => setTempValue(e.target.value),
onBlur: () => setFilters(tempValue),
value: tempValue,
})
}
而不是做:
<Filter
value={filters.name}
setFilters={value =>
setFilters(filters => ({ ...filters, name: value }))
}
/>
这样做:
const setFilters = value => setFilters(filters => ({ ...filters, name: value }))
const { resetTempFilter, getInputProps } = useFilter(value, setFilters)
...
<input {...getInputProps()} />
在这种情况下,您可以更容易地通过更改key
道具(基于React中的协调工作方式,称为"重置状态"技术(来重新实例化子对象:
const [resetKey, setResetKey] = useState(0);
const doReset = setResetKey(key => key + 1);
<Filter
key={`name-filter-${resetKey}`}
...
/>
<Filter
key={`code-filter-${resetKey}`}
...
/>
<button onClick={doReset}>Reset!</button>
这不仅更容易实现。它也将同样适用于任何您无法修改(出于任何原因(的有状态组件。