简体   繁体   中英

Change state from reducer not from root state using React-Redux when data is inherited

Good afternoon. I am writing an application using react-redux and faced a dilemma. I have already re-thought it several times and can't choose how to organize the project and data structure correctly and conveniently. Design data by inheriting or composing data. I initially went along the path of composition, but I realized that it is inconvenient when there is a one-to-one relationship. I decided to change it to inheritance, because it seemed logical from the point of view of data organization, but there was a big difficulty with reducers , more precisely, I am confused that it turns out to be a single root reducer with a lot of actionTypes keys. I remember about performance, when elements inherit a data chain from a common ancestor, that this is very bad. And yet I chose this path and I have a question: Please tell me if it is possible to split into several reducers for each level of nesting data. Example

onst initState: IPages = {
  idActive: 0,
  pages: [
    {
      id: 1,
      title: `Tab #1`,
      workspace: {
        idActiveDraggableElements: [],
        idActiveLines: [],
        attributes: {
          height: string,
          width: string,
          viewBox: [0, 0, 5000, 5000]
        },
        draggableElements: [], // more data
        lines: [],  // more data
      }
    },
  ]
}

Reducer:

export function pagesReducer(
  state: IPages = initState,
  action: IPageActionTypes
) {
  switch (action.type) {
    case "ADD_PAGE":
      let uniqId = getUniqKeyIdOfArrayList(state.pages);
      return {
      ...state,
      pages: state.pages.concat({id:uniqId, title:`Вкладка - ${uniqId}`})
    }
    case "REMOVE_PAGE": return {
      ...state,
      pages: state.pages.filter(item => item.id !== action.id)
    }
    case "CHOSE_PAGE": return {
      ...state,
      idActive: action.id
    }
    case "RENAME_PAGE":
      let indexPage = state.pages.findIndex(item => item.id === action.id);
      state.pages[indexPage].title = action.title;
      return {
      ...state
      }

      // ===================
      // LONG LIST WHAT BAD...
      // It's a bad idea to add editing to the `workspace` field and then `draggableElements`. `lines` 
      // ... but I understand that this will happen, because I don't know if there is another way.
    default:
      return state
  }
}

Can I edit the `workspace' node without updating the entire application state?

Thanks you for any help.

For data modeling aspect for a 1-to-1 relationship, you can choose either to reference by id or to embed the data. It depends on your query pattern.

In your case which is embedding, you can make use of memoized selectors .

Ideally, since you have an idActive , update your pages data structure to be an object instead of a list.

Like so:

{
  pages: {
    '1': {
       workspace: { ... },  
    }
  }
}

Then for your reducer, think of it as slicing a tree (or nested attribute). Your reducer would then look something like:

function workspaceReducer(state, action) {
  // TODO
}

function pagesReducer(state, action) {
  switch (action.type) {
    case 'UPDATE_WORKSPACE': {
      const { id } = action;
      const page = Object.assign({}, state.pages[id]);
      return {
        ...state,
        pages: {
          ...state.pages,
          [id]: {
             ...page,
             workspace: workspaceReducer(page.workspace, action)
          }
        }
      }
    }
  }
} 

Then to prevent unnecessary re-renders, using memoized selectors, it would be like:

import { createSelector } from 'reselect';

const pages = state => state.pages;
const activePage = state => state.idActive;

const getActivePage = createSelector(
  activePage,
  pages,
  (id, pages) => pages[id]
);

const getWorkspace = createSelector(
  getActivePage,
  page => page.workspace
);

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