commit 67b341af1061f5dcc6cd3ba03711a88f74ebf10f Author: Felix Edel Date: Mon Sep 28 11:02:40 2020 +0200 Avoid state mutations in build reducers When updating the redux state one should not directly touch the state but rather create a copy of the object first, so redux can efficiently check if anything has changed and the UI components should be updated. This avoids mutating the state.builds property directly and uses the spread operators instead to copy the builds dictionary and replace (or enhance) the data of the build in question. Since the build reducers are doing rather simple state changes, I also decided to drop the usage of the immutability-helper library here and use plain JavaScript instead as I find this much more readable and straightforward. Change-Id: I88c68fed99b21bc9a3682e952499fb4fdf74e2d0 diff --git a/web/src/reducers/build.js b/web/src/reducers/build.js index d7c8933..ab33951 100644 --- a/web/src/reducers/build.js +++ b/web/src/reducers/build.js @@ -12,73 +12,81 @@ // License for the specific language governing permissions and limitations // under the License. -import update from 'immutability-helper' - import { BUILD_FETCH_FAIL, BUILD_FETCH_REQUEST, BUILD_FETCH_SUCCESS, - BUILDSET_FETCH_FAIL, BUILDSET_FETCH_REQUEST, BUILDSET_FETCH_SUCCESS, - BUILD_OUTPUT_FAIL, BUILD_OUTPUT_REQUEST, BUILD_OUTPUT_SUCCESS, - BUILD_MANIFEST_FAIL, BUILD_MANIFEST_REQUEST, BUILD_MANIFEST_SUCCESS, } from '../actions/build' - -export default (state = { - isFetching: false, - isFetchingOutput: false, - isFetchingManifest: false, - builds: {}, - buildsets: {}, -}, action) => { +export default ( + state = { + isFetching: false, + isFetchingOutput: false, + isFetchingManifest: false, + builds: {}, + buildsets: {}, + }, + action +) => { switch (action.type) { - case BUILD_FETCH_REQUEST: - case BUILDSET_FETCH_REQUEST: - return update(state, {$merge: {isFetching: true}}) - case BUILD_FETCH_SUCCESS: - state.builds = update( - state.builds, {$merge: {[action.buildId]: action.build}}) - return update(state, {$merge: {isFetching: false}}) - case BUILDSET_FETCH_SUCCESS: - return update(state, {$merge: { - isFetching: false, - buildsets: update(state.buildsets, {$merge: { - [action.buildsetId]: action.buildset}}) - }}) - case BUILD_FETCH_FAIL: - case BUILDSET_FETCH_FAIL: - return update(state, {$merge: {isFetching: false}}) - - case BUILD_OUTPUT_REQUEST: - return update(state, {$merge: {isFetchingOutput: true}}) - case BUILD_OUTPUT_SUCCESS: - state.builds = update( - state.builds, {[action.buildId]: {$merge: {errorIds: action.errorIds, - hosts: action.hosts, - output: action.output}}}) - return update(state, {$merge: {isFetchingOutput: false}}) - case BUILD_OUTPUT_FAIL: - return update(state, {$merge: {isFetchingOutput: false}}) - - case BUILD_MANIFEST_REQUEST: - return update(state, {$merge: {isFetchingManifest: true}}) - case BUILD_MANIFEST_SUCCESS: - state.builds = update( - state.builds, {[action.buildId]: {$merge: {manifest: action.manifest}}}) - return update(state, {$merge: {isFetchingManifest: false}}) - case BUILD_MANIFEST_FAIL: - return update(state, {$merge: {isFetchingManifest: false}}) - - default: - return state + case BUILD_FETCH_REQUEST: + case BUILDSET_FETCH_REQUEST: + return { ...state, isFetching: true } + case BUILD_FETCH_SUCCESS: + return { + ...state, + builds: { ...state.builds, [action.buildId]: action.build }, + isFetching: false, + } + case BUILDSET_FETCH_SUCCESS: + return { + ...state, + buildsets: { ...state.buildsets, [action.buildsetId]: action.buildset }, + isFetching: false, + } + case BUILD_FETCH_FAIL: + case BUILDSET_FETCH_FAIL: + return { ...state, isFetching: false } + case BUILD_OUTPUT_REQUEST: + return { ...state, isFetchingOutput: true } + case BUILD_OUTPUT_SUCCESS: { + const buildsWithOutput = { + ...state.builds, + [action.buildId]: { + ...state.builds[action.buildId], + errorIds: action.errorIds, + hosts: action.hosts, + output: action.output, + }, + } + return { ...state, builds: buildsWithOutput, isFetchingOutput: false } + } + case BUILD_OUTPUT_FAIL: + return { ...state, isFetchingOutput: false } + case BUILD_MANIFEST_REQUEST: + return { ...state, isFetchingManifest: true } + case BUILD_MANIFEST_SUCCESS: { + const buildsWithManifest = { + ...state.builds, + [action.buildId]: { + ...state.builds[action.buildId], + manifest: action.manifest, + }, + } + return { ...state, builds: buildsWithManifest, isFetchingManifest: false } + } + case BUILD_MANIFEST_FAIL: + return { ...state, isFetchingManifest: false } + default: + return state } }