React 和 Redux 工具包:当我想使用过滤器操作时松开状态
React and Redux toolkit : loose the state when I want to use filter action
我正在尝试创建一个按钮来根据输入的值过滤数据。
我在 header 组件中创建了一个按钮,在主组件中创建了我的项目列表。
我的问题是,当我从 header 中的按钮发送 'projectFilter' 操作时,它过滤了数据,但我丢失了初始状态。
有我的项目切片器
import { createSlice } from "@reduxjs/toolkit";
let lastId = 2;
const slice = createSlice({
name: "projects",
initialState: [],
reducers: {
projectAdded: (state, action) => {
state.push({
id: ++lastId,
name: action.payload.name,
gender: action.payload.gender,
});
},
projectFilter: (state, action) => {
return state.filter((project) => project.id === action.payload.id);
},
},
});
export const { projectAdded, projectFilter } = slice.actions;
export default slice.reducer;
添加项目和筛选项目有我的两个按钮
function Header() {
const dispatch = useDispatch();
const [value, setValue] = useState(0);
return (
<div className="header">
<button
onClick={() =>
dispatch(
projectAdded({ name: "project name", gender: "project gender" })
)
}
>
Add project
</button>
<input type="number" onChange={(event) => setValue(event.target.value)} />
<button onClick={() => dispatch(projectFilter({ id: Number(value) }))}>
Filter
</button>
</div>
);
}
export default Header;
最后是我在页面中呈现的项目列表
function Main() {
const projects = useSelector((state) => state.projects);
return (
<div className="main">
{projects.map((project) => (
<p key={project.id}>
{project.id} {project.name} {project.gender}
</p>
))}
</div>
);
}
export default Main;
你能帮我在不丢失所有状态的情况下过滤数据吗?提前谢谢你
操作与选择器
当你发送一个动作时,你正在永久地改变状态。您不希望仅将 state.projects
替换为与当前过滤器匹配的项目。您希望将所有项目都保留在该州,而 select 只保留匹配的项目。这是您在 Main
.
中使用 useSelector
中的 selector 函数执行的操作
存储当前过滤器
您的 selector 函数需要知道过滤器 ID 才能过滤匹配项。您可以通过 useState
将该 id 存储在组件中,或者您可以将过滤器 id 作为 属性 存储在您的 redux 存储中(在项目切片或另一个切片中)。
如果您正在编辑过滤器并显示同一组件的过滤结果,我会推荐 useState
方法。使用两个单独的组件,您仍然可以这样做,但是状态必须存储在共享 parent 中并通过 props 向下传递。我不知道你的 Main
和 Header
组件之间的关系,所以对于这种情况,我建议将当前过滤器存储在 redux 中。您将 dispatch
设置当前过滤器的操作。基本上,该操作只是更新存储的过滤器 ID。应用过滤器的工作仍然转到 selector.
lastId
Reducer 不应依赖外部状态。您不希望 lastId
只是文件中的某个变量。您需要从状态本身获取一个 id。您可以在当前项目中查找最大 id,或者您可以将 lastId
存储为状态中的 属性。
代码
切片
import { createSlice } from "@reduxjs/toolkit";
const initialState: {
projects: [],
lastId: 2, // why not 0 or 1?
filter: null, // is just the id right now, but could be a complex object
}
const slice = createSlice({
name: "projects",
initialState,
reducers: {
projectAdded: (state, action) => {
state.projects.push({
id: ++state.lastId,
name: action.payload.name,
gender: action.payload.gender,
});
},
projectFilter: (state, action) => {
state.filter = action.payload.id;
},
},
});
export const { projectAdded, projectFilter } = slice.actions;
export default slice.reducer;
Header
无变化
主要
function Main() {
const projects = useSelector(
// could move this function to another file
// this could be written more concisely, but I'm trying to be clear instead
(state) => {
const all = state.projects.projects;
const filterId = state.projects.filter;
if ( filterId === null ) {
return all;
}
else {
return all.filter( project => project.id === filterId );
}
});
return (
<div className="main">
{projects.map((project) => (
<p key={project.id}>
{project.id} {project.name} {project.gender}
</p>
))}
</div>
);
}
export default Main;
我正在尝试创建一个按钮来根据输入的值过滤数据。
我在 header 组件中创建了一个按钮,在主组件中创建了我的项目列表。
我的问题是,当我从 header 中的按钮发送 'projectFilter' 操作时,它过滤了数据,但我丢失了初始状态。
有我的项目切片器
import { createSlice } from "@reduxjs/toolkit";
let lastId = 2;
const slice = createSlice({
name: "projects",
initialState: [],
reducers: {
projectAdded: (state, action) => {
state.push({
id: ++lastId,
name: action.payload.name,
gender: action.payload.gender,
});
},
projectFilter: (state, action) => {
return state.filter((project) => project.id === action.payload.id);
},
},
});
export const { projectAdded, projectFilter } = slice.actions;
export default slice.reducer;
添加项目和筛选项目有我的两个按钮
function Header() {
const dispatch = useDispatch();
const [value, setValue] = useState(0);
return (
<div className="header">
<button
onClick={() =>
dispatch(
projectAdded({ name: "project name", gender: "project gender" })
)
}
>
Add project
</button>
<input type="number" onChange={(event) => setValue(event.target.value)} />
<button onClick={() => dispatch(projectFilter({ id: Number(value) }))}>
Filter
</button>
</div>
);
}
export default Header;
最后是我在页面中呈现的项目列表
function Main() {
const projects = useSelector((state) => state.projects);
return (
<div className="main">
{projects.map((project) => (
<p key={project.id}>
{project.id} {project.name} {project.gender}
</p>
))}
</div>
);
}
export default Main;
你能帮我在不丢失所有状态的情况下过滤数据吗?提前谢谢你
操作与选择器
当你发送一个动作时,你正在永久地改变状态。您不希望仅将 state.projects
替换为与当前过滤器匹配的项目。您希望将所有项目都保留在该州,而 select 只保留匹配的项目。这是您在 Main
.
useSelector
中的 selector 函数执行的操作
存储当前过滤器
您的 selector 函数需要知道过滤器 ID 才能过滤匹配项。您可以通过 useState
将该 id 存储在组件中,或者您可以将过滤器 id 作为 属性 存储在您的 redux 存储中(在项目切片或另一个切片中)。
如果您正在编辑过滤器并显示同一组件的过滤结果,我会推荐 useState
方法。使用两个单独的组件,您仍然可以这样做,但是状态必须存储在共享 parent 中并通过 props 向下传递。我不知道你的 Main
和 Header
组件之间的关系,所以对于这种情况,我建议将当前过滤器存储在 redux 中。您将 dispatch
设置当前过滤器的操作。基本上,该操作只是更新存储的过滤器 ID。应用过滤器的工作仍然转到 selector.
lastId
Reducer 不应依赖外部状态。您不希望 lastId
只是文件中的某个变量。您需要从状态本身获取一个 id。您可以在当前项目中查找最大 id,或者您可以将 lastId
存储为状态中的 属性。
代码
切片
import { createSlice } from "@reduxjs/toolkit";
const initialState: {
projects: [],
lastId: 2, // why not 0 or 1?
filter: null, // is just the id right now, but could be a complex object
}
const slice = createSlice({
name: "projects",
initialState,
reducers: {
projectAdded: (state, action) => {
state.projects.push({
id: ++state.lastId,
name: action.payload.name,
gender: action.payload.gender,
});
},
projectFilter: (state, action) => {
state.filter = action.payload.id;
},
},
});
export const { projectAdded, projectFilter } = slice.actions;
export default slice.reducer;
Header
无变化主要
function Main() {
const projects = useSelector(
// could move this function to another file
// this could be written more concisely, but I'm trying to be clear instead
(state) => {
const all = state.projects.projects;
const filterId = state.projects.filter;
if ( filterId === null ) {
return all;
}
else {
return all.filter( project => project.id === filterId );
}
});
return (
<div className="main">
{projects.map((project) => (
<p key={project.id}>
{project.id} {project.name} {project.gender}
</p>
))}
</div>
);
}
export default Main;