防止在全局上下文中重新呈现功能组件更新状态
Prevent Re-Render of Functional Component Updating State in a Global Context
我有一个上下文正在提供给我的整个应用程序。在上下文中是数组的状态,其中包含用于过滤应用程序上显示的数据的键。我正在使用 this 下拉选择器,它是一个树选择器,它接受 JSON 数据并显示它。它有一个示例,说明如何在父项呈现时防止重新呈现,但我无法使其适用于功能组件。
发生了什么,当在下拉列表中进行选择时,它会将所有当前选择的内容传递给 onchange 处理程序,并且在处理程序中它将上下文中的状态数组设置为下拉列表传递的数组。状态更改导致下拉组件重新呈现 App 传递的初始数据作为道具重置为未检查任何内容。
我曾研究过使用 React.memo 来尝试阻止下拉菜单重新呈现,但无法使其正常工作。防止重新呈现下拉列表是解决此问题的方案 A。
全局上下文代码
import React, {useState} from 'react';
//Typing for global state
type globalStateObj = {
Fleets: string[];
updateFleets: (value: string[])=>void;
}
//Context creation with initial
export const stateContext = React.createContext<globalStateObj>({
Fleets: [""],
updateFleets: ()=>{}
})
export const GlobalStateProvider = (props: {children: any}) =>{
const [fleets, setFleets] = useState([""]);//states should match stateContext
//Handlers for updating state
const updateFleetHandler = (value: string[])=>{
setFleets(value);
}
//Setting values to state and handlers
const conextValue: globalStateObj = {
Fleets: fleets,
updateFleets: updateFleetHandler,
}
return(
<stateContext.Provider value={conextValue}>
{props.children}
</stateContext.Provider>
)
};
下拉组件代码
import { stateContext } from "../GlobalState";
import './DropdownFilterBar.scss';
import "react-dropdown-tree-select/dist/styles.css";
interface DropdownFilterBar_Props{
data: any[]
}
export const DropdownFilterBar = (props: DropdownFilterBar_Props) =>{
const globalState = useContext(stateContext);
const handleChange = (selected: any, allchecked: TreeNode[]) =>{
let results = allchecked.map(({value})=>value);
console.log(results);
globalState.updateFleets(results);
}
const texts: TextProps = {
placeholder:"Fleets",
inlineSearchPlaceholder:"Search"
}
return(
<div className="DropDownFilterBar">
<DropdownTreeSelect
data={props.data}
onChange={(selected, allchecked) =>{handleChange(selected, allchecked)}}
className="fleet-selector"
inlineSearchInput={true}
texts={texts}
/>
</div>
)
};
App.tsx ContextProvider所在位置
<div className="App">
<Container className="themed-container">
<Row className='navRow'>
<Col><TopNavBar/></Col>
</Row>
<GlobalStateProvider>
<Row className="DropdownFilterRow">
<Col><DropdownFilterBar data={DropdownFilterData}/></Col>
</Row>
<Row>
<Col className="dashboard">
<Routes>
<Route path="/overview" element={<Home/>} />
...
我最终使用的解决方案是 useMemo 挂钩而不是 React.Memo。即使使用 React.Memo,useContext 也会强制使用 re-render。我意识到 useMemo 可以用来记忆依赖于 props.data 的 JSX 元素。下拉组件代码现在看起来像这样
const dropdown = useMemo(()=>{
return(
<DropdownTreeSelect
data={props.data}
onChange={(selected, allchecked) =>{handleChange(selected, allchecked)}}
className="fleet-selector"
inlineSearchInput={true}
texts={texts}
/>
)}, [props.data]);
return(
<div className="DropDownFilterBar">
{dropdown}
</div>
)
我有一个上下文正在提供给我的整个应用程序。在上下文中是数组的状态,其中包含用于过滤应用程序上显示的数据的键。我正在使用 this 下拉选择器,它是一个树选择器,它接受 JSON 数据并显示它。它有一个示例,说明如何在父项呈现时防止重新呈现,但我无法使其适用于功能组件。
发生了什么,当在下拉列表中进行选择时,它会将所有当前选择的内容传递给 onchange 处理程序,并且在处理程序中它将上下文中的状态数组设置为下拉列表传递的数组。状态更改导致下拉组件重新呈现 App 传递的初始数据作为道具重置为未检查任何内容。
我曾研究过使用 React.memo 来尝试阻止下拉菜单重新呈现,但无法使其正常工作。防止重新呈现下拉列表是解决此问题的方案 A。
全局上下文代码
import React, {useState} from 'react';
//Typing for global state
type globalStateObj = {
Fleets: string[];
updateFleets: (value: string[])=>void;
}
//Context creation with initial
export const stateContext = React.createContext<globalStateObj>({
Fleets: [""],
updateFleets: ()=>{}
})
export const GlobalStateProvider = (props: {children: any}) =>{
const [fleets, setFleets] = useState([""]);//states should match stateContext
//Handlers for updating state
const updateFleetHandler = (value: string[])=>{
setFleets(value);
}
//Setting values to state and handlers
const conextValue: globalStateObj = {
Fleets: fleets,
updateFleets: updateFleetHandler,
}
return(
<stateContext.Provider value={conextValue}>
{props.children}
</stateContext.Provider>
)
};
下拉组件代码
import { stateContext } from "../GlobalState";
import './DropdownFilterBar.scss';
import "react-dropdown-tree-select/dist/styles.css";
interface DropdownFilterBar_Props{
data: any[]
}
export const DropdownFilterBar = (props: DropdownFilterBar_Props) =>{
const globalState = useContext(stateContext);
const handleChange = (selected: any, allchecked: TreeNode[]) =>{
let results = allchecked.map(({value})=>value);
console.log(results);
globalState.updateFleets(results);
}
const texts: TextProps = {
placeholder:"Fleets",
inlineSearchPlaceholder:"Search"
}
return(
<div className="DropDownFilterBar">
<DropdownTreeSelect
data={props.data}
onChange={(selected, allchecked) =>{handleChange(selected, allchecked)}}
className="fleet-selector"
inlineSearchInput={true}
texts={texts}
/>
</div>
)
};
App.tsx ContextProvider所在位置
<div className="App">
<Container className="themed-container">
<Row className='navRow'>
<Col><TopNavBar/></Col>
</Row>
<GlobalStateProvider>
<Row className="DropdownFilterRow">
<Col><DropdownFilterBar data={DropdownFilterData}/></Col>
</Row>
<Row>
<Col className="dashboard">
<Routes>
<Route path="/overview" element={<Home/>} />
...
我最终使用的解决方案是 useMemo 挂钩而不是 React.Memo。即使使用 React.Memo,useContext 也会强制使用 re-render。我意识到 useMemo 可以用来记忆依赖于 props.data 的 JSX 元素。下拉组件代码现在看起来像这样
const dropdown = useMemo(()=>{
return(
<DropdownTreeSelect
data={props.data}
onChange={(selected, allchecked) =>{handleChange(selected, allchecked)}}
className="fleet-selector"
inlineSearchInput={true}
texts={texts}
/>
)}, [props.data]);
return(
<div className="DropDownFilterBar">
{dropdown}
</div>
)