简体   繁体   中英

Functional component props/state/store not updated in function - what's a viable alternative?

First off some description of what I need to achieve. I show information in front-end (React) that mostly corresponds to database rows and the user can do regular CRUD operations on those objects. However, I also add some dummy rows into the JSON that I send to front-end because there are some objects that are "defaults" and should not be inserted into the database unless the user actually wants to modify them. So what I need to do is once a user wants to modify a "default" object in front-end, I first have to POST that object to a specific endpoint that copies it from constants to the database and only then follow that up with the request to modify that row.

Secondly, the architecture around this. For storing the state of the rows in front-end I'm using Redux via easy-peasy and I have a thunk for doing the first saving before modifying. Once a user wants to edit a "default" object anywhere in the UI (there are about 20 different ways of editing an object), the flow of the program looks something like this:

  1. User edits something and presses "save"
  2. Thunk is called in the save function and await ed
  3. Thunk POSTs to backend to insert the object into database and return the corresponding row
  4. Backend responds with the ID-s of the rows
  5. Thunk calls action and updates these objects in store with correct ID-s
  6. Thunk returns and the function pointer moves back to the modifying function
  7. The modifying function makes another request with the correct ID-s
  8. The modifying function updates the store with the modified values

Now, the problem I run into is from step 5 to 7, because the component looks basically like this:

const Foo = () => {
    const insertToDatabaseIfNecessary = useStoreActions((actions) => actions.baz.insertIfNecessary)
    const items = useStoreState((state) => state.baz.items);

    const onSave = async () => {
        await insertToDatabaseIfNecessary();

        // do the actual modifying thing here
        axios.post(...items);
    }

    return (
        <button onClick={onSave}>Save!</button>
    );
}

If you know functional components better than I do, then you know that in onSave() the insertToDatabaseIfNecessary() will update the values in Redux store, but when we get to the actual modifying and post(...items) then the values that are POSTed are not updated because they will be updated in the next time the component is called. They would be updated if this was a class-based component, but easy-peasy has no support for class-based components. I guess one way would be to use class-based components and Redux directly but I have feeling there might be a different pattern that I could use to solve my issue without resorting to class-based components.

The question: Is there a sane way of doing this with functional components?

Thunks in easy-peasy can handle asynchronous events, so you should put your axios post in there eg

insertToDatabaseIfNecessary : thunk(async (actions, payload) => {
    // First update the data on the server
    await axios.post(payload.items);

    // Assuming that the post succeeds, now dispatch and action to update your store.
    // (You'd want to check your post succeeded before doing this...)
    actions.updateYourStoreData(payload);
})

This easy-peasy thunk will wait for the async post to finish, so you can use the action as follows in your Foo component:

insertToDatabaseIfNecessary();

You will not need to await it or use the onSave function in your Foo component.

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