0

We develop a reusable table-like component with Reacts functional component style. The table holds, manages and validates it's state with React.useReducer. In each row there are several input-fields, checkboxes and action-buttons to modifiy the row/table-state.

Now there is a Save-Button somewhere else in the GUI (not a child of the table). How can the state be retrived from the table, so that it can be send (along with some other data) to a REST-Endpoint for persistence?

Our actual solution is a callback-function that will be set as a prop on the table. This function is called from inside the table-component after each rendering to publish a copy of the current state. Now the owner of this callback function gets and holds this data so that it is available in the scope of the Save-Button.

function ComponentWrapper(props)
{
    const dataRef = React.useRef(props.initialData);

    function onDataUpdate(newData) {
        dataRef.current = newDate;
    }
    
    function saveData() {
        // send dataRef.current to REST-Endpoint
    }
    
    return (
        <div>
            <MyTable onDataUpdate={onDataUpdate}></MyTable>
            ...
            <button onClick={(e) => sendData()} name="save">Save</button>
        </div>
    );
}
    
function MyTable(props)
{
    const [state, dispatch] = useReducer(..., props.initialData)

    // ... some code to dispatch state changing actions

    useEffect(() => {
        const copyOfState = { ...state }
        props.onDataUpdate(copyOfState);
    });
   
    return (
        // table markup goes here ...
    );
}

This actually works but we believe that there might be a better way for such usecases. We don't want to lift the state from the table to the ComponentWrapper because the table should be reusable and the save button might be located on a completly different place in the GUI (e.g. in a toolbar or a menu).

Any ideas on this? Thanks in advance.

Ogod
  • 878
  • 1
  • 7
  • 15

1 Answers1

1

If your table is currently managing its own state, then you need to lift that state up, or move it into some global store. Passing the save function as a callback from some component up the tree that is also a parent of the save button will work, as you said.

But a more elegant and user friendly solution would be to either use some context, or use redux.

With context, your save function can pass that value to the context object, which can be retrieved elsewhere in the tree. There are many nice articles on how to do that - here is one, and here is another.

Redux is similar, and has become a favorite for doing exactly what you're trying to do. You can use a redux reducer to save the table data to the global store, then your 'save' button can call retrieve this data from the store and send it to your REST endpoint, regardless of its relationship in the tree to the table. In large apps where state needs to be coordinated across many components, its definitely a top choice.

Seth Lutske
  • 9,154
  • 5
  • 29
  • 78
  • Thanks for your answer. Is there really no other/better official way than lifting up the state to some parent or the root-component of the app? So every consumer of our table-component have to correctly setup a react-context-provider / redux-store with the needed reducer and action boilerplate before they can fully use it. I am wondering how it is possible to build a reusable component if state handling is a bit more complicated than just storing some values? I am actually not very experienced with React. – Ogod Aug 06 '20 at 16:37
  • I'm confused. you say "every consumer of our table-component" - you mean every parent? The `MyTable` itself will consume the context, or pull from the redux store. The `MyTable` can be reused in many places in this way. As far as your questions, the most 'official' ways are context and redux, with redux really being an industry standard at this point. try it out, i think you'll like it. – Seth Lutske Aug 06 '20 at 18:34
  • With "every consumer of our table-component" i meant every user who want to integrate out component in their app. We will give React context+reducers a try. – Ogod Aug 08 '20 at 07:52