neutrino
neutrino

Reputation: 924

How to refine React modal to allow user to enter new data into state

How does one take user data from the page and use it to create elements in a react.js program?

I have a file, app.js. The first things declared in the file are a couple of constants, for toy data:

const book1 = [
    {id: uuid(), content: 'reflections'}
];
const book2 = [
    {id: uuid(), content: 'arising'},
]

and a single constant pulling them in as columns


const clusterColumns =
    {
        [uuid()]: {
            name: 'Book 1',
            items: book1
        },
        [uuid()]: {
            name: 'Book 2',
            items: book2
        },
    };

and a third const that cleans up the data as i move it around on the page


const onDragEnd = (result, columns, setColumns ) => {
    if(!result.destination ) return;
    const {source, destination} = result;
    if (source.droppableId!==destination.droppableId) {
        const sourceColumn = columns[source.droppableId];
        const destColumn = columns[destination.droppableId];
        const sourceItems = [...sourceColumn.items];
        const destItems = [...destColumn.items];
        const [removed] = sourceItems.splice(source.index, 1);
        destItems.splice(destination.index, 0, removed);
        setColumns({
            ...columns,
            [source.droppableId]:{
                ...sourceColumn,
                items: sourceItems,
            },
            [destination.droppableId]:{
                ...destColumn,
                items: destItems
            }
        })
    }
    else {
        const column = columns[source.droppableId];
        const copiedItems = [...column.items];
        const [removed] = copiedItems.splice(source.index, 1);
        copiedItems.splice(destination.index, 0, removed)
        setColumns({
            ...columns,
            [source.droppableId]: {
                ...column,
                items: copiedItems
            }
        })
    }
};

a main bit of the app.js file is a nested function that builds drag and drop elements with some style, pulling in the toy data

function App() {
    const [columns, setColumns] = useState(clusterColumns);
    return (
        <div>
            <div style={{display: 'flex', justifyContent: 'left', height: '95%', position: "relative",
                top: 5, left: 90, opacity: '27%'}}>
                <DragDropContext onDragEnd={result => onDragEnd(result, columns, setColumns)}>
                    {Object.entries(columns).map(([id, column]) => {
                        return (
                            <div style={{display: 'flex', flexDirection: 'column', alignItems:'center',
                                fontFamily: 'Montez, sans-serif', color: '#913aff', fontSize: 27, padding:5, borderRadius: '19px',
                            }}><h2  style={{fontSize:(19*3), height: 45}}>{column.name}</h2>
                                <h2  style={{fontSize:(19*3), height: 45, top:'9px', position:'absolute', opacity:'60%', color:'#ffa0f9'}}>{column.name}</h2>
                                <div style={{margin: 2}}>
                                    <Droppable droppableId={id} key={id} >
                                        {(provided, snapshot) => {
                                            return (
                                                <div {...provided.droppableProps}
                                                     ref={provided.innerRef}
                                                     style={{
                                                         padding: 9,
                                                         width: 190,
                                                         minHeight: 9,
                                                         opacity: '95%',
                                                         borderRadius: '9px',
                                                         background: 'linear-gradient(to right bottom, rgba(196, 181, 255, 1), rgba(132,47,0,0.27)'}} >
                                                         {column.items.map((item, index) => {
                                                            return (
                                                                <Draggable key={item.id} draggableId={item.id} index={index}>
                                                                    {(provided, snapshot) => {
                                                                        return (
                                                                            <div
                                                                                ref={provided.innerRef}
                                                                                {...provided.draggableProps}
                                                                                {...provided.dragHandleProps}
                                                                                style={{
                                                                                    opacity: '95%',
                                                                                    userSelect: 'none',
                                                                                    padding: 19,
                                                                                    margin: '0px 0px 3px 0px',
                                                                                    backgroundColor: snapshot.isDragging ? '#54ffff':'#b3f542',
                                                                                    background: 'linear-gradient(to right bottom, rgba(84, 255, 255, 0.63), rgba(179, 245, 66, 0.81)',
                                                                                    color: 'rgb(115,38,0)' ,
                                                                                    fontFamily: 'Montez',
                                                                                    fontSize: 36,
                                                                                    borderRadius: '9px',
                                                                                    ...provided.draggableProps.style
                                                                                }}>
                                                                                {item.content}
                                                                            </div>
                                                                        )
                                                                    }}
                                                                </Draggable>
                                                            )
                                                        }
                                                    )}
                                                    {provided.placeholder}
                                                </div>
                                            )
                                        }}
                                    </Droppable>
                                </div>
                            </div>
                        )
                    })}
                </DragDropContext>
            </div>
        </div>
    );
}

My question is, what might I build in, to replace the toy data with a button that the user enters new data into, which then might appear on-screen? I have tried putting a second program, for adding a cell.

class Cell extends React.Component {
    render() {
        return (
            <form>

                <input
                    type="text" style={{
                        display:'flex',
                    position:'relative',
                        top: '-360px',
                    right:'95px',
                    fontFamily: "VT323",
                    width:'144px',
                    fontSize:'36px',
                    color: 'rgb(115,38,0)',
                    opacity:'60%',
                    borderRadius: '9px',
                    height: '45px',
                    background: 'radial-gradient(rgba(196, 181, 255, .9), rgba(168,255,0,0.19)',
                    borderColor: 'rgba(255,255,255,0)'
                }}
                />
            </form>
        );
    }
}

But it is a simple user form; the data entered should effective replace the toy data filling the consts at the top of the first program.

Upvotes: 0

Views: 442

Answers (1)

SILENT
SILENT

Reputation: 4268

Sample of adding a very basic input to add new items

Create a component for your input fields

function AddBookItem({ onAdd }) {
    const [value, setValue] = useState('');
    const onChange = ({ target: { value }}) => setValue(value);
    return (
        <div>
            <input value={value} onChange={onChange} placeholder="Book Item" />
            <button onClick={onAdd(value)}>Add book item</button>
        </div>
    );
}

Create a function to handle adding values to your parent state

const onAdd = (value) => () => {
        setColumns((columns) => {
            const nC = {...columns};
            // get first book id
            const id = clusterKeys[0];
            const c = { ...columns[id] }
            // console.log({ c });
            const ci = [...c.items];
            ci.push({ id: uuid(), content: value });
            c.items = ci;
            nC[id] = c;
            return nC;
        })
    }

Add your new component to your app

<AddBookItem onAdd={onAdd} />

https://codesandbox.io/s/stackoverflow-add-example-kfk2e

Upvotes: 1

Related Questions