Search code examples
javascriptangularreactjsreact-dom

How to update props of React Component rendered using ReactDOM.render()


I am trying to integrate react into my angularjs webapp.

In my controller I create the component, which initially has array props that are empty. When the app is done initializing, I want to update the props again. Do I do this by calling ReactDOM.render() again or can I keep a reference to this instance and just do something like updateProps(newProps)?

This is called from my controller:

ReactDOM.render(
    <NavBar
        currencyTabs = {[]}
    />, document.getElementById("navbar-root")
);

And then when the data is done loading i need to update the currencyTabs with a full array ...

I understand how react components props update from parent to child, but I don't quite get how I can do this from plain JS.


Solution

  • There is no magic at work here, you just need to re-render it.

    Just wrapper your rendering into a function, eg:

    function renderReactNavbar( tabs = [] ) {
      ReactDOM.render(
        <NavBar
            currencyTabs = { tabs }
        />, document.getElementById("navbar-root")
      );
    
    }
    

    and call it after you load / update your data.

    Alternatively, you choose to load your data from inside react, which might be a better choice in the long run.

    If you have internal state, this might be somewhat harder to handle. You could consider moving to a props only component (but since you don't share any relevant code of your react component, it is hard to say)

    A small example of how it could look would be

    // the render method, takes a component and props, and renders it to the page
    function renderComponent( component, props ) {
      const target = document.querySelector('#container');
      ReactDOM.render( React.createElement( component, props ), target );
    }
    
    // gets the tabs from the input field, splits based on ,
    function getTabsFromInput() {
      return document.querySelector('#tabs').value.split(',');
    }
    
    // small presentational component, shows the tabs and redirects selection changes through a callback
    const Tabs = ({ tabs, selectedTab, onSelectionChanged }) => {
      return tabs && <div>{ tabs.map( (tab, key) => {
        return <h1 key={key} className={classNames( { 'active': key === selectedTab } ) } onClick={ () => onSelectionChanged( key ) }>{ tab }</h1>;
      } ) }</div>;
    };
    
    // some initiations
    window.addEventListener('load', function() {
      // keep a local variable with the data
      let defaultProps = {
        onSelectionChanged: updateSelection,
        selectedTab: 0,
        tabs: getTabsFromInput()
      };
    
      // handles selection changes
      function updateSelection( newTab ) {
        defaultProps = {...defaultProps, selectedTab: newTab };
        renderComponent( Tabs, defaultProps );
      }
    
      // adds an event listener for click events to initiate tab changes
      document.querySelector('#updateTabs').addEventListener('click', function() {
        defaultProps = {...defaultProps, tabs: getTabsFromInput() };
        // render on update
        renderComponent( Tabs, defaultProps );
      });
    
      // initial render
      renderComponent( Tabs, defaultProps );
    });
    .active {
      background-color: blue;
    }
    <script id="react" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.js"></script>
    <script id="react-dom" src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.js"></script>
    <script id="classnames" src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.5/index.js"></script><div id="container"></div>
    <input type="text" value="tab1,tab2" id="tabs" />
    <button id="updateTabs" type="button">Update tabs</button>