Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react recursive functional component update state

I trying to do parent and child recursive state using React. I have added App3 which has initial state should maintain entire state into it. I have no idea how can I add update delete with this when it comes to recursive.

I have tried using https://hookstate.js.org/docs/recursive-state/ But due to some limitation I want to use react without any third party packages.

How can I perform CRUD for the recursive state

const data = {
    op: 0,
    values: [
        {
            op: 0,
            value: {
                values: [
                    {
                        op: 2,
                        value: {
                            values: []
                        }
                    }
                ]
            }
        },
        {
            op: 1,
            value: {
                values: []
            }
        }
    ]
}
function App3() {

    const [mainState, setMainState] = React.useState(data);

    return (
        <div>
            {
                mainState.values.map((x, i) => {
                    return <RecursiveFn key={i} value={x}></RecursiveFn>
                })
            }
          <button>Add</button>
        <hr/>
        <div><pre>
         {JSON.stringify(mainState)}</pre></div>
        </div>
    )
}

function RecursiveFn(props) {
    
    return (
        <div style={{ padding:5,margin:10,paddingLeft: 20,border:'1px solid black' }}>
            <div> OP -

                <input type={'text'} value={props.value.op}></input>
            </div>
            {props.value.value && props.value.value.values ? props.value.value.values.map((x, i) => <RecursiveFn value={x}></RecursiveFn>) : null}
            <button>Add</button>
            <button>Delete</button>
        </div>
    );
}

ReactDOM.render(<App3 />,
document.getElementById("root"))
<script src="https://unpkg.com/[email protected]/umd/react.production.min.js"> 
</script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>


   <div id="root"></app>
like image 466
Gautam Parmar Avatar asked Dec 20 '25 19:12

Gautam Parmar


1 Answers

Since the component structure is recursive, its state updates have to happen in a recursive way as well. You can keep a path to update using an array and use it to identify the correct update level:

const data = {
  op: 0,
  value: {
    values: [
      {
        op: 0,
        value: {
          values: [
            { op: 2, value: { values: [{ op: 3, value: { values: [] } }] } }
          ]
        }
      },
      { op: 3, value: { values: [{ op: 3, value: { values: [] } }] } }
    ]
  }
};

const ACTIONS = {
  CHANGE: "change",
  ADD: "add",
  DELETE: "delete"
};

function App3() {
  const [mainState, setMainState] = React.useState(data);

  const handleChange = (path, value, action) => {
    setMainState((prevState) => {
      return getNestedUpdate(prevState, [...path], value, action);
    });
  };

  const performAction = (state, value, action, deleteIndex) => {
    switch (action) {
      case ACTIONS.CHANGE:
        return {
          ...state,
          op: value
        };
      case ACTIONS.ADD:
        return {
          ...state,
          value: {
            ...state.value,
            values: [
              ...state.value.values,
              { op: "new-entry", value: { values: [] } }
            ]
          }
        };
      case ACTIONS.DELETE:
        return {
          ...state,
          value: {
            ...state.value,
            values: state.value.values.filter(
              (item, itemIndex) => itemIndex !== deleteIndex
            )
          }
        };
      default:
        return state;
    }
  };

  const getNestedUpdate = (state, path, value, action) => {
    if (path.length === 0) {
      return performAction(state, value, action);
    }

    if (action === ACTIONS.DELETE && path.length === 1) {
      return performAction(state, value, action, path.shift(0));
    }

    const level = path.shift(0);

    return {
      ...state,
      value: {
        ...state.value,
        values: state.value.values.map((item, itemIndex) =>
          itemIndex === level
            ? getNestedUpdate(item, path, value, action)
            : item
        )
      }
    };
  };

  return (
    <div>
      {mainState.value.values.map((x, i) => {
        return (
          <RecursiveFn
            key={i}
            value={x}
            path={[i]}
            handleChange={handleChange}
          ></RecursiveFn>
        );
      })}
      <button>Add</button>
      <hr />
      <div>
        <pre>{JSON.stringify(mainState, null, 2)}</pre>
      </div>
    </div>
  );
}

function RecursiveFn(props) {
  return (
    <div
      style={{
        padding: 5,
        margin: 10,
        paddingLeft: 20,
        border: "1px solid black"
      }}
      key={props.path}
    >
      <div>
        {" "}
        OP -
        <input
          type={"text"}
          value={props.value.op}
          onChange={(e) =>
            props.handleChange(props.path, e.target.value, ACTIONS.CHANGE)
          }
        ></input>
      </div>
      {props.value.value && props.value.value.values
        ? props.value.value.values.map((x, i) => (
            <RecursiveFn
              key={i}
              value={x}
              path={[...props.path, i]}
              handleChange={props.handleChange}
            ></RecursiveFn>
          ))
        : null}
      <button onClick={() => props.handleChange(props.path, null, ACTIONS.ADD)}>
        Add
      </button>
      <button
        onClick={() => props.handleChange(props.path, null, ACTIONS.DELETE)}
      >
        Delete
      </button>
    </div>
  );
}

ReactDOM.render(<App3 />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>
like image 146
Amila Senadheera Avatar answered Dec 23 '25 09:12

Amila Senadheera



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!