Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Context API is slow

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

like image 569
partyelite Avatar asked Apr 20 '26 23:04

partyelite


1 Answers

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

like image 151
sonicmario Avatar answered Apr 22 '26 22:04

sonicmario



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!