New Vs Edit Components in React

I have been working on this app taht will store medical resources for students and physicians to reference quickly…react is a great choice due to the speed of the SPA. I’m a little stuck on how to progress now.

I have complex object (nested objects/arrays with nested objects/arrays), and spent about 8 days creating the “new” form which ended up being about 5 components with some conditional rendering depending on the type of new object being added. Here’s the form… each of the dropdowns expands, one has an embedded form as well.

Next, I’m trying to add editing features to my app. I will need to use a different database query of course to update rather than create. I’m wondering if I should handle all that conditionally within one component … or have it as two separate concerns.

I have done the recipe front end react challenge, but this is more complex. I’m not sure of there is a standard answer or if it can be done both ways…or if there is a best practice.

Also, I’m not sure why I’m having a mental block with this, maybe because it’s react and not EJS

If you’re going to edit or add new, create that action (method) within your state handler (whatever component is holding all of the objects you’re displaying). Pass down this method from your state handler to whatever components require the action (maybe a modal with a new/edit button). Then have your database return all of the documents you want to display and replace your state so those changes propagate automatically to any components that utilize that state.

You can also have the DB send back just the updated document and then update your state by cloning your state, iterating over the cloned object, checking if a similar document exists and, if so, update and, if not, add. Then set your state to the new cloned object and it should propagate down.

1 Like

I easily lifted my state to a higher level component for populating the “New” form, but now…ugh…I have to lift all my functions from the local component to a higher level one to propagate entry text upwards. Maybe this is a good time for me to experiment with the new Context API in react?

It looks like you are trying to maintain a consistent state across components, with many moving parts. The context api will help alleviate some of this headache.

But it will easily turn to spaghetti if you want to sync state “upwards”. It’s best that state changes for a particular task is only updated in one place.

It’s doable, but I feel in the long run it will be harder to troubleshoot. React works best when you keep data flow unidirectional, from parent to child.

Going upwards is fine for single, or maybe even double nested components. I wouldn’t recommend it otherwise from a purely maintenance standpoint.

React context api is best for “drilling down” props / state.

To be frank, it looks like you may have to start looking into redux for state management. This way each component only interacts with the redux state, keeping your logic flow clear, and properly separating your concerns.

As usual thanks for your input .I didn’t mean that I wanted to move state upwards (even though that’s what I typed), I meant specifically dealing with form entries. Currently I manage it in the form component because that’s where it is and the state is there so it’s easy. Now that state is in the App.js, my change handler doesn’t work as expected, so I need to address that in the top level. Make sense?

OK, I see. So all your state lives in the App.js. That makes it your global store so redux won’t provide much benefit for state management then. I thought you were separating state amongst components.

I agree with you, context will be the way going forward. You could also look into creating a higher order component that deals exclusively with state management. Then all your handlers could live there. Just as thought.

now i’m just confusing myself. I’ve worked for an hour trying to lift the state into the app for little things like handling field chnages for the form…but since i have both the DB fetched resourcdes as well as a blank object for a new state, i’m having trouble writing this code so it would work with editing existing or adding new.

I feel like it’s going in circles. Gonna take another break!

If i keep state in a sub component utnil the new resource is created or an existing one is edited, whats the best way to get that completed object back to synch with the state? I know there are a couple ways but now it’s getting pretty confusing to me.

I’m not following this part. Is the empty object the fallback until App.js fetches resources, or that you have an empty state object in that component?

Are you tracking id’s? Then you could merge back into the top level state, or append the new state.

But then you’d have two different copies of a particular state. But as long as it doesn’t have to stay in sync with another component until you merge back, it’ll be fine.

You’d also be changing global state locally, so it might cause issues tracking down bugs later.

Have you tried using a higher order component with the context api? If you wrap your state and handlers in a higher order component, you will then be able to work with each wrapped component as if the state and handlers were local. Plus you’d only need to change one line in your components:

export default App

// to 
export default withStateHandler(App)

This will alleviate the state and handler lifting/drilling. In case you missed it, see if this section helps you. https://reactjs.org/docs/context.html#consuming-context-with-a-hoc

I think a weekend of camping will help digest this…

Do you think at this point it’d be better to dive into redux?

Some fresh air should definitely help!

I think that if you’re ok with keeping all your state and handlers in a HOC, and you don’t need all the tracking abilities of redux or it’s ecosystem, then you don’t need redux.

An HOC with state and handlers is like a mini-redux anyways. So something like this should really get you moving

export function withStateHandlers(Component) {
  // ...and returns another component...
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.handleChange = this.handleChange.bind(this);
      this.state = {};
    }

    handleChange() {
      this.setState({});
    }

    render() {
      const handlers = { handleChange: this.handleChange };
      const ThemeContext = React.createContext({ state: this.state, handlers });
      return (
        <ThemeContext.Consumer>
          {context => (
            <Component
              {...props}
              state={context.state}
              handlers={context.handlers}
            />
          )}
        </ThemeContext.Consumer>
      );
    }
  };
}

then, anywhere you want to access state or use a handler, you use it as if it was local

// stateless
const App = ({ state, handlers }) => {
   // here you have access

  handlers.handleChange()
}

// class
class App extends Component {
  // here you also have access

  return (
  <input handleChange={this.props.handlers.handleChange} />
  )
}

// but you must export the wrapped component
// to get access to the wrapped context
export default withStateHandlers(App)

I think this would be your most elegant solution. You’ll get the benefit of keeping state changes in one place like with redux, while being able to connect to it from other components without having to drill down props or lift state.

OK, so the fresh air was awesome and I thought about this project all weekend. B ut when I got back, my code was spaghetti and I reverted back to the prior code where state is in the form level.

I don’t know how to proceed, so i think i’m going to jupm back into the web dev bootcamp course where they build out the full stack with react & redux and see what I learn.

Unless you can suggest another direction.