简体   繁体   中英

What is the proper way to control react components based on redux state

I think this is more of a conceptual/architecture question but I will include code samples to help explain the question. I have a normalized redux state where the entities state slice looks like this:

entities: {
    projects: {
        [id]: {...},
        [id]: {...},
        ...
    },
    assignments: {
        [id]: {...},
        [id]: {...},
        ...
    }
}

And an individual assignment looks like this:

    {
        id: 1,
        name: 'assignment 1',
        status: 'active',
        deadline: '01-01-2020'
    }

I fetch this data from a backend DB. I am trying to figure out the proper way to handle the process of updating this data, keeping the UI responsive, and keeping my redux state in sync with the backend.

A specific example is a react component for displaying an individual assignment that has a picker/radio buttons to change the status between:

    const statusOptions = {
        'active',
        'pending',
        'complete'
    }

The options I can see are:

1) Set the value of the picker as the props.assignment.status value, and in the onChange of the picker/selector dispatch an updateAssignment() action where a saga/thunk sends the POST request and immediately triggers a fetchAssignment() action which will send a GET request and update the redux state and in turn the component will re render.

The problem with this is the redux update takes too long so the UI appears laggy and the controlled input will revert to the old selection until the new props are passed in.

2) Set the local component state based on the redux state like this:

    state = { status: this.props.assignment.status }

And then set the value of the picker based on the local state, which would provide near instant UI updates on a value change.

The problem I see here is I am pretty sure this is a react anti-pattern, and I would have to use getDerivedStateFromProps() or something similar to make sure the local state stays in sync with the redux state. Plus I really like the 'single source of truth' idea and I feel like this option would invalidate that.

3) set the value of the picker based on props.assignment.status and in the onChange handler of the picker clone the assignment object, update the status attribute, and then immediately send an updateAssignment() action that merges the locally created assignment object into the state.

After that send the POST request to the server and if it fails somehow revert the redux state to the prior state, basically removing the locally added assignment object. This seems kind of hacky though maybe?

Is there any agreed upon best practices for updating redux data while maintaining a single source of truth, snappy UI, and clean code?

The first part of (2) seems to me the right way.

In ComponentDidMount (or, even better, in App.js, when the app is starting) you fetch the data from the database to the redux state, and set the local state from it.

Then you maintain the data locally, and dispatch the proper action that will update the redux state and the database.

In shouldComponentUpdate you need to prevent updates that happen following this redux update: you will check if the values of the props have changed.

In componentDidUpdate you will update the state if the props change.

The last thing to take care of is getting data updates following database changes that happen by other instances of the app running on other smartphones, or by other sources of data, if this may happen. In firebase, for example, you do that by listening to relevant app changes. I don't know if this is relevant here.

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