在响应路由器更改时维护每个子组件的上下文数据
maintain the context data for each child component on react router change
我是 React 的初学者,正在开发 React 应用程序,我使用上下文来维护按钮状态,按钮状态可以处于开始、加载、停止的任何一个阶段。
我正在将上下文传递给应用程序组件,并有一个反应路由器根据路由渲染组件。我通过循环遍历每张卡片都有一个按钮组件的数据来渲染卡片组件。
单击 card1 按钮时,按钮 1 应进入加载阶段 10-15 秒,具体取决于 api 响应时间。一旦响应到来,它应该处于停止阶段。如果一起单击,对于 button2 和 button3 也是类似的。现在,当我立即单击 button1 和 button2 时似乎工作正常
但是当我同时单击 2 个按钮并移动到另一条路线并快速返回时,我没有看到我的按钮处于加载状态,尽管 api 响应仍在等待中。我应该看到它们处于加载状态,当响应到来时,我应该看到它们处于开始或停止阶段。
我知道我可以使用本地或会话存储,但由于某些代码限制我不想这样做。任何帮助将不胜感激。
这是堆栈闪电战 link : https://stackblitz.com/edit/node-3t59mt?file=src/App.js
Github Link: https://github.com/mehulk05/react-context-api
Button.jsx
import React, { useContext,useEffect, useState } from 'react'
import DbContext from '../Context/sharedContext'
function Button(props) {
console.log(props)
const {
requestStartDbObj,
setRequestStartDbObj
} = useContext(DbContext)
const [state, setstate] = useState(props.text?.status ?? "start")
useEffect(() => {
setstate(props.text?.status??"start")
return () => {
}
}, [state])
console.log(requestStartDbObj)
const start = ()=>{
setRequestStartDbObj({id:props.status.id, status:"loading"})
setstate("loading")
setTimeout(()=>{
setstate("stop")
setRequestStartDbObj({id:props.status.id, status:"stop"})
},5000)
}
return (
<div>
<button onClick={start}>{state}1</button>
</div>
)
}
export default Button
Card.jsx
function Card(props) {
const {
requestStartDbObj,
} = useContext(DbContext)
return (
<div>
<h1>{props.data.name}</h1>
<Button status={props.data} text={requestStartDbObj} />
</div>
)
}
Component1.jsx
function Component1() {
let data = [
{
id: 1,
name: "card1",
status: "start",
},
{
id: 2,
name: "card2",
status: "start",
},
{
id: 3,
name: "card3",
status: "start",
},
];
return (
<div>
<h1>Hello</h1>
{data.map((d, i) => (
<Card key={i} data={d} />
))}
</div>
);
}
ComponentWrapper.jsx
<h3>Wrpper</h3>
<Routes>
<Route path="/" element={<Component1 />} />
<Route path="about" element={<Component2 />} />
</Routes>
</div>
App.js
function App() {
return (
<div className="App">
<BrowserRouter>
<Link to="/">Home</Link> <br></br>
<Link to="/about">Comp 2</Link>
<DbProvider>
<ComponentWrapper/>
</DbProvider>
</BrowserRouter>
</div>
);
}
问题是您的 DbProvider
上下文不是状态的真实来源,它不是维护 requestStartDbObj
状态的组件。每个 Button
都在本地复制状态并使用自己的 start
函数。每个Button
也是替换上下文的requestStartDbObj
状态,所以当切换回主路径时所有按钮获得相同的初始状态值。离开主路径后,Button
组件将被卸载,因此超时时的状态更新将丢失。
您应该将 start
逻辑移至 sharedContext
,以便 DbProvider
保持对状态更新的控制。 start
应该使用一个 id
参数,以便它可以正确更新该特定对象的 status
。
DbProvider
const DbProvider = (props) => {
const [requestStartDbObj, setRequestStartDbObj] = useState({});
const { children } = props;
const start = (id) => {
setRequestStartDbObj((state) => ({
...state,
[id]: { status: "loading" }
}));
setTimeout(() => {
setRequestStartDbObj((state) => ({
...state,
[id]: { status: "stop" }
}));
}, 5000);
};
return (
<DbContext.Provider
value={{
requestStartDbObj,
start
}}
>
{children}
</DbContext.Provider>
);
};
卡片
仅将映射时从 Component1
传递的 data
道具传递给 Button
id
道具。
function Card({ data }) {
return (
<div>
<h1>{data.name}</h1>
<Button id={data.id} />
</div>
);
}
按钮
使用 id
属性传递给上下文提供的 start
函数。还可以使用 id
访问当前状态。
function Button({ id }) {
const { requestStartDbObj, start } = useContext(DbContext);
return (
<div>
<button onClick={() => start(id)}>
{requestStartDbObj[id]?.status || "start"}-{id}
</button>
</div>
);
}
我是 React 的初学者,正在开发 React 应用程序,我使用上下文来维护按钮状态,按钮状态可以处于开始、加载、停止的任何一个阶段。
我正在将上下文传递给应用程序组件,并有一个反应路由器根据路由渲染组件。我通过循环遍历每张卡片都有一个按钮组件的数据来渲染卡片组件。
单击 card1 按钮时,按钮 1 应进入加载阶段 10-15 秒,具体取决于 api 响应时间。一旦响应到来,它应该处于停止阶段。如果一起单击,对于 button2 和 button3 也是类似的。现在,当我立即单击 button1 和 button2 时似乎工作正常
但是当我同时单击 2 个按钮并移动到另一条路线并快速返回时,我没有看到我的按钮处于加载状态,尽管 api 响应仍在等待中。我应该看到它们处于加载状态,当响应到来时,我应该看到它们处于开始或停止阶段。
我知道我可以使用本地或会话存储,但由于某些代码限制我不想这样做。任何帮助将不胜感激。
这是堆栈闪电战 link : https://stackblitz.com/edit/node-3t59mt?file=src/App.js Github Link: https://github.com/mehulk05/react-context-api
Button.jsx
import React, { useContext,useEffect, useState } from 'react'
import DbContext from '../Context/sharedContext'
function Button(props) {
console.log(props)
const {
requestStartDbObj,
setRequestStartDbObj
} = useContext(DbContext)
const [state, setstate] = useState(props.text?.status ?? "start")
useEffect(() => {
setstate(props.text?.status??"start")
return () => {
}
}, [state])
console.log(requestStartDbObj)
const start = ()=>{
setRequestStartDbObj({id:props.status.id, status:"loading"})
setstate("loading")
setTimeout(()=>{
setstate("stop")
setRequestStartDbObj({id:props.status.id, status:"stop"})
},5000)
}
return (
<div>
<button onClick={start}>{state}1</button>
</div>
)
}
export default Button
Card.jsx
function Card(props) {
const {
requestStartDbObj,
} = useContext(DbContext)
return (
<div>
<h1>{props.data.name}</h1>
<Button status={props.data} text={requestStartDbObj} />
</div>
)
}
Component1.jsx
function Component1() {
let data = [
{
id: 1,
name: "card1",
status: "start",
},
{
id: 2,
name: "card2",
status: "start",
},
{
id: 3,
name: "card3",
status: "start",
},
];
return (
<div>
<h1>Hello</h1>
{data.map((d, i) => (
<Card key={i} data={d} />
))}
</div>
);
}
ComponentWrapper.jsx
<h3>Wrpper</h3>
<Routes>
<Route path="/" element={<Component1 />} />
<Route path="about" element={<Component2 />} />
</Routes>
</div>
App.js
function App() {
return (
<div className="App">
<BrowserRouter>
<Link to="/">Home</Link> <br></br>
<Link to="/about">Comp 2</Link>
<DbProvider>
<ComponentWrapper/>
</DbProvider>
</BrowserRouter>
</div>
);
}
问题是您的 DbProvider
上下文不是状态的真实来源,它不是维护 requestStartDbObj
状态的组件。每个 Button
都在本地复制状态并使用自己的 start
函数。每个Button
也是替换上下文的requestStartDbObj
状态,所以当切换回主路径时所有按钮获得相同的初始状态值。离开主路径后,Button
组件将被卸载,因此超时时的状态更新将丢失。
您应该将 start
逻辑移至 sharedContext
,以便 DbProvider
保持对状态更新的控制。 start
应该使用一个 id
参数,以便它可以正确更新该特定对象的 status
。
DbProvider
const DbProvider = (props) => {
const [requestStartDbObj, setRequestStartDbObj] = useState({});
const { children } = props;
const start = (id) => {
setRequestStartDbObj((state) => ({
...state,
[id]: { status: "loading" }
}));
setTimeout(() => {
setRequestStartDbObj((state) => ({
...state,
[id]: { status: "stop" }
}));
}, 5000);
};
return (
<DbContext.Provider
value={{
requestStartDbObj,
start
}}
>
{children}
</DbContext.Provider>
);
};
卡片
仅将映射时从 Component1
传递的 data
道具传递给 Button
id
道具。
function Card({ data }) {
return (
<div>
<h1>{data.name}</h1>
<Button id={data.id} />
</div>
);
}
按钮
使用 id
属性传递给上下文提供的 start
函数。还可以使用 id
访问当前状态。
function Button({ id }) {
const { requestStartDbObj, start } = useContext(DbContext);
return (
<div>
<button onClick={() => start(id)}>
{requestStartDbObj[id]?.status || "start"}-{id}
</button>
</div>
);
}