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