如何使用useReducer在React JS中存储状态?



我有一个组件(我们称它为祖父组件),默认情况下它有一个输入框(>)箭头和添加按钮,每当我点击添加按钮,将生成一个新的输入框。现在让我们回到主体部分每当我点击(>)按钮,一个新组件应该打开,其中也有一个默认输入框,(>将呈现相同的添加按钮,如果我在其中添加一些内容并单击(>)按钮,则会打开一个新组件并打开相同的输入框,(>)图标和添加按钮

现在的情况是,它形成了一个树形结构

const finalStructure = {
"category": {
"agriculture" : ["5 hectares" , "10 hectates" , "15 hectares"],
"automobile" : ["bus" , "car" , "truck"],
"farming": ["wheat" , "rice" , "maida"]
}, 
"product": {
"face": "white-toned",
"skin": "healthy"
}
};

仔细看这里"类别"是我在祖父组件和[" agriculture "中输入的第一个值、";automobile"、";automotive"]是我在父组件中输入的三个选项,然后对应的值是我在子组件中输入的。

问题是:我如何维护这三个组件之间的关系[祖父母,父母和孩子]到目前为止,我尝试使用声明和分配空对象来输入值,但是如何存储值,以便如果我将来引用它,值仍然保留。

您可以使用useContext()useReducer()来实现这一点。

useContext()钩子是为子组件提供相关值的。这是在Reactcross-component状态管理中有效使用useReducer()的关键。

但是在使用useContext()之前,我们必须先使用createContext()

createContext()示例:

// ParentComponent.js
export const context = React.createContext({ myDefault: "value" });
...
const { Provider } = context;
return (
<>
<Provider value={{ myCustom: "value" }}>
<MyComponent />
</Provder>
<NoProviderComponent />
</>
)

现在Provider组件内部的所有组件都可以访问提供的值{myCustom: "value"},而Provider之外的组件只能访问{myDefault: "value"}

useContext()示例:

// MyComponent
import { context } from "./ParentComponent.js";
const value = useContext(context);
console.log(value);       // will log `{ myCustom: "value" }`
// NoProviderComponent
import { context } from "./ParentComponent.js";
const value = useContext(context);
console.log(value);       // will log `{ myDefault: "value" }`

useReducer()的帮助下,你可以将状态处理集中在一个简单的函数中,通常(redux)它们与action对象一起工作,这些对象总是有一个type和某种value/payload

这里我有一个状态的例子,它是一个文件对象列表。

useReducer()示例:

const [state, dispatch] = useReducer((state, action) => {
const { type, payload } = action;
switch(action) {
case "ADD_FILE":
return [
...state,
payload
];
default:
return state;
}
}, []);
...
return (
<button onClick={() =>
dispatch({ type: "ADD_FILE", payload: YOUR_FILE_OBJECT})}>
Add me on click!
</button>
)
结果

您可以将所有这些组合在一个store.js文件中:

import { createContext, useReducer } from "react";
const initialState = {
category: {},
product: {},
};
const store = createContext();
const { Provider } = store;
const StateProvider = ({ children }) => {
const [state, dispatch] = useReducer((state, action) => {
switch (action.type) {
case "ADD_NEW_CATEGORY":
return {
...state,
category: {
...state.category,
[action.value]: [],
},
};
case "ADD_TO_CATEGORY":
return {
...state,
category: {
...state.category,
[action.value]: [...state.category[action.value], action.payload],
},
};
case "ADD_PRODUCT":
return {
...state,
product: {
...state.product,
...action.payload,
},
};
default:
return state;
}
}, initialState);
return <Provider value={{ state, dispatch }}>{children}</Provider>;
};
export { store, StateProvider };

在你的index.js中使用:

import { createRoot } from "react-dom/client";
import App from './App';
import { StateProvider } from './store.js';
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<StateProvider>
<App />
</StateProvider>
);

现在你可以像这样在任何子组件中编辑状态:

import { useContext } from "react";
import { store } from "./store.js";
const ChildComponent = () => {
const globalState = useContext(store);
const { state, dispatch } = globalState;
// Adding new category
dispatch({
type: "ADD_NEW_CATEGORY",
value: "farming",
});
// Adding to category
dispatch({
type: "ADD_TO_CATEGORY",
value: "farming",
payload: ["wheat", "rice", "maida"],
});
// Adding product
dispatch({
type: "ADD_PRODUCT",
payload: { face: "white-toned" },
});
};