skip to Main Content

I have tested two ways to switch between screens for simple application (Max 3 modes/screens). Still learning the ropes and focusing on practicing with useState and maybe useEffect for some cases.

Would like to know if there are other ways (without using routers) for switching between modes/screens.

Practice Run #1:

Objective, create a common Modal component so I can keep screen design in one high level component. This modal contains a close button, and renders provided children. Data context stays with parent. The Add and Edit events have their own states. At the moment, I don’t care to keep data if someone closes and opens the model again.

Cons: I feel there are too many isShow?? tests in this method. Ideally, all state can go with parent. If this goes above 3x modes/screens – it would get a bit clunky with switch statement.

// Simple modal with isShown, close button and children
const Modal = ({ isShown, onClose, children }) => {
  return (
    <>
      {isShown && (
        <div className='modal-overlay'>
          <div className='modal'>
            {children}
            <button onClick={onClose}>X</button>
          </div>
        </div>
      )}
    </>
  )
}

// Simple add event comp, takes onSubmit callback to send data to parent
const AddEvent = ({ onSubmit }) => {
  const [name, setName] = useState('')
  console.log('Render Add Event')

  return (
    <>
      <div>
        <p>Add Event Mode:</p>
        <input
          type='text'
          name='name'
          placeholder='set your name'
          onChange={(e) => setName(e.target.value)}
          value={name}
        />
        <button id='some' onClick={() => onSubmit(name)}>
          Send Name to Parent
        </button>
      </div>
    </>
  )
}

// Simple edit event comp, takes originalData from parent and onSubmit callback to send modified data to parent
const EditEvent = ({ originalData, onSubmit }) => {
  const [name, setName] = useState(originalData)
  console.log('Render Edit Event')

  return (
    <>
      <div>
        <p>Edit Event Mode:</p>
        <input
          type='text'
          name='name'
          placeholder='set your name'
          onChange={(e) => setName(e.target.value)}
          value={name}
        />
        <button id='some' onClick={() => onSubmit(name)}>
          Send Data to Parent
        </button>
      </div>
    </>
  )
}

// The main app comp. state for modal, data and step (add, edit).
export default function App() {
  const [showModal, toggleShowModal] = useState(false)
  const [parentData, setparentData] = useState('')
  const [step, setStep] = useState({ add: false, edit: false })
  
  // Main function to toggle event mode.
  const toogleEventMode = (e) => {
    console.log('Switching modes')
    switch (e.target.name) {
      case 'add':
        setStep({ add: true, edit: false })
        toggleShowModal(true)
        break
      case 'edit':
        setStep({ add: false, edit: true })
        toggleShowModal(true)
        break
    }
  }
  return (
    <>
      <h3>Click on Add Event to add an event, and then Edit</h3>
      <Modal isShown={showModal} onClose={() => toggleShowModal(false)}>
        {step.add && (
          <AddEvent
            onSubmit={(dataFromAddEvent) => setparentData(dataFromAddEvent)}
          />
        )}
        {step.edit && (
          <EditEvent
            onSubmit={(dataFromEditEvent) => setparentData(dataFromEditEvent)}
            originalData={parentData}
          />
        )}
      </Modal>
      <div className='card'>
        <button name='add' onClick={(e) => toogleEventMode(e)}>
          Add Event
        </button>
        <button name='edit' onClick={(e) => toogleEventMode(e)}>
          Edit Event
        </button>
      </div>
    </>
  )
}

2

Answers


  1. Chosen as BEST ANSWER

    The second method is much simpler, but useful for three action sections. Add, Edit and Delete. The example I worked on is only for Add/Edit.

    Here I can add a Layout component, that returns children. Used purely for styling.

    // purely for styling multiple pages. Cann be added like <Layout><SomeChildComp></Layout>
    export const Layout = ({ children }) => {
      return <div className='modal'>{children}</div>
    }
    
    
    const AddEvent = ({ isShown, onClose, onSubmit }) => {
      const [name, setName] = useState('')
      console.log('Render Add Event')
    
      return (
        <>
          {isShown && (
            <>
              <p>Add Event Mode:</p>
              <input
                type='text'
                name='name'
                placeholder='set your name'
                onChange={(e) => setName(e.target.value)}
                value={name}
              />
              <button onClick={() => onSubmit(name)}>Send Name to Parent</button>
              <button onClick={onClose}>Close</button>
            </>
          )}
        </>
      )
    }
    
    
    const EditEvent = ({ isShown, originalData, onClose, onSubmit }) => {
      const [newName, setNewName] = useState('')
      console.log('Render Edit Event', newName)
    
      useEffect(() => {
        setNewName(originalData)
      }, [originalData])
    
      return (
        <>
          {isShown && (
            <div>
              <p>Edit Event Mode:</p>
              <input
                type='text'
                name='name'
                placeholder='set your name'
                onChange={(e) => setNewName(e.target.value)}
                value={newName}
              />
              <button id='some' onClick={() => onSubmit(newName)}>
                Send Data to Parent
              </button>
              <button onClick={onClose}>Close</button>
            </div>
          )}
        </>
      )
    }
    
    
    
    
    export default function App() {
      const [parentData, setparentData] = useState('')
      const [step, setStep] = useState({ add: false, edit: false })
      console.log('Parent Name: ', parentData)
    
      const toogleEventMode = (e) => {
        console.log('Switching modes')
        switch (e.target.name) {
          case 'add':
            setStep({ add: true, edit: false })
            toggleShowModal(true)
            break
          case 'edit':
            setStep({ add: false, edit: true })
            toggleShowModal(true)
            break
        }
      }
      return (
        <>
          <h3>Data Add/Edit demo</h3>
         
            <AddEvent
              isShown={step.add}
              onSubmit={(dataFromAddEvent) => setparentData(dataFromAddEvent)}
              onClose={() => setStep({ add: false })}
            />
        
          <EditEvent
            isShown={step.edit}
            onSubmit={(dataFromEditEvent) => setparentData(dataFromEditEvent)}
            originalData={parentData}
            onClose={() => setStep({ edit: false })}
          />
        
            <button name='add' onClick={(e) => toogleEventMode(e)}>
              Add Event
            </button>
            <button name='edit' onClick={(e) => toogleEventMode(e)}>
              Edit Event
            </button>
        </>
      )
    }


  2. The following shows how to use useReducer – albeit a bit clunky for now. Will polish this as use case is defined further.

    END of this Q&A post.

    import { useReducer, useState } from 'react'
    import './App.css'
    // Same AddEvent as before
    import { AddEvent } from './AddEvent'
    // Same EditEvent as before
    import { EditEvent } from './EditEvent'
    // Same Layout as before
    import { Layout } from './Layout'
    
    // Reducer function for switching modes
    function reducerSwitchMode(state, action) {
      console.log('Switching modes')
      console.log(state, action)
      switch (action) {
        case 'addEvent':
          return {
            add: true,
            edit: false,
          }
        case 'editEvent':
          return {
            edit: true,
            add: false,
          }
        case 'closeAll':
          return {
            edit: false,
            add: false,
          }
      }
    }
    
    export default function App() {
      const [parentData, setparentData] = useState('')
      // useReducer
      const [state, dispatchMode] = useReducer(reducerSwitchMode, {
        add: false,
        edit: false,
      })
    
    
      return (
        <>
          <h3>Data Add/Edit demo</h3>
          <Layout>
            <AddEvent
              isShown={state.add}
              onSubmit={(dataFromAddEvent) => setparentData(dataFromAddEvent)}
              onClose={() => dispatchMode('closeAll')}
            />
          </Layout>
          <EditEvent
            isShown={state.edit}
            onSubmit={(dataFromEditEvent) => setparentData(dataFromEditEvent)}
            originalData={parentData}
            onClose={() => dispatchMode('closeAll')}
          />
          <div className='card'>
            <button name='add' onClick={() => dispatchMode('addEvent')}>
              Add Event
            </button>
            <button name='edit' onClick={() => dispatchMode('editEvent')}>
              Edit Event
            </button>
          </div>
        </>
      )
    }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search