I'm experimenting with new Context API and hooks. I've created an app with sidebar (treeview), footer and main content page. I have a context provider
const ContextProvider: FunctionComponent = (props) => {
const [selected, setSelected] = useState(undefined);
const [treeNodes, setTreeNodes] = useState([]);
return (
<MyContext.Provider
value={{
actions: {
setSelected,
setTreeNodes
},
selected,
treeNodes
}}
>
{props.children}
</MyContext.Provider>
);
Im my content component I have a DetailsList (Office Fabric UI) with about 1000 items. When I click on the item in the list I want to update selected item in context. This works but it is really slow. It takes about 0,5-1 seconds to select item in the list. The list is virtualized. I have tried it on production build. Thing are a bit better but there is a noticable lag when clicking on list. Footer is consuming myContext to display information about selected item.
Here is a bit of code from my component
const cntx = useContext(MyContext);
const onClick = (item) => {
cntx.actions.setSelected(item);
};
Am I using the context wrong?
I've created a sample sandbox to demonstrate.. You can scroll to about 100-th index and click a couple of times to see how it gets unresponsive.
https://codesandbox.io/s/0m4nqxp4m0
Is this a problem with Fabric DetailsList? Does it reRender to many times? I believe the problem is with "complex" DatePicker component but I don't understand why does DetailsList get rerenderd? It's not using any of context properties within a render function. I would expect only Footer component to rerender on every context change
Caveats Because context uses reference identity to determine when to re-render, there are some gotchas that could trigger unintentional renders in consumers when a provider’s parent re-renders. For example, the code below will re-render all consumers every time the Provider re-renders because a new object is always created for value:
class App extends React.Component {
render() {
return (
<Provider value={{something: 'something'}}>
<Toolbar />
</Provider>
);
}
}
To get around this, lift the value into the parent’s state:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'},
};
}
render() {
return (
<Provider value={this.state.value}>
<Toolbar />
</Provider>
);
}
}
https://reactjs.org/docs/context.html#caveats
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With