简体   繁体   中英

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/react@16.7.0-alpha.0/umd/react.production.min.js"> </script> <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.production.min.js"></script> <div id="root"></app>

For those who are looking for the full solutions. I have modified the answer of @Amila Senadheera.

 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: [] } }] } }] } }; function App4() { const [mainState, setMainState] = React.useState(data); const handleChange = (path, value) => { setMainState((prevState) => { return getNestedUpdate(prevState, [...path], value); }); }; const getNestedUpdate = (state, path, value) => { if (path.length === 0) { return {...state, op: value }; } const level = path.shift(0); return {...state, value: {...state.value, values: state.value.values.map((item, itemIndex) => itemIndex === level? getNestedUpdate(item, path, value): item ) } }; }; const handleAddItem = (path, value) => { setMainState((prevState) => { return AddItem(prevState, [...path], value); }); }; const AddItem = (state, path, value) => { if (path.length === 0) { if (state.value && state.value.values) { return {...state, value: { values: [...state.value.values, value] } }; } else { const arr = []; return {...state, value: { values: [...arr, value] } }; } } const level = path.shift(0); return {...state, value: {...state.value, values: state.value.values.map((item, itemIndex) => itemIndex === level? AddItem(item, path, value): item ) } }; }; const AddMainItem = () => { setMainState((prevState) => ({...prevState, value: { values: [...prevState.value.values, { type: 'group', op: 'new group' }] } })) } return ( <div> {mainState.value.values.map((x, i) => { return ( <RecursiveGroup key={i} value={x} path={[i]} handleChange={handleChange} handleAddItem={handleAddItem} ></RecursiveGroup> ); })} <button onClick={AddMainItem}>Add</button> <hr /> <div> <pre>{JSON.stringify(mainState, null, 2)}</pre> </div> </div> ); } function RecursiveGroup(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)} ></input> </div> {props.value.value && props.value.value.values? props.value.value.values.map((x, i) => ( x.type == 'group'? <RecursiveGroup key={i} value={x} path={[...props.path, i]} handleChange={props.handleChange} handleAddItem={props.handleAddItem} ></RecursiveGroup>: <div key={i} style={{ padding: 5, margin: 10, paddingLeft: 20, border: "1px solid black" }}>I am rule</div> )): null} <button onClick={(e) => props.handleAddItem(props.path, { type: 'group', op: 'group' })}>Add Group</button> <button onClick={(e) => props.handleAddItem(props.path, { type: 'Rule', op: 'Rule' })}>Add Rule</button> </div> ); } ReactDOM.render(<App4 />, document.getElementById("root"))
 <script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.production.min.js"> </script> <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.production.min.js"></script> <div id="root"></app>

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: [] } } ] } } ] } }; function App3() { const [mainState, setMainState] = React.useState(data); const handleChange = (path, value) => { setMainState((prevState) => { return getNestedUpdate(prevState, [...path], value); }); }; const getNestedUpdate = (state, path, value) => { if (path.length === 0) { return {...state, op: value }; } const level = path.shift(0); return {...state, value: {...state.value, values: state.value.values.map((item, itemIndex) => itemIndex === level? getNestedUpdate(item, path, value): 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)} ></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>Add</button> <button>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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM