-1

I am using react redux/toolkit in my application, I assume that I can manage share state between sibling components with redux state. For this purpose, I have implemented a redux slice with state and reducer, and trying to update the state via calling reducer. It works for one component , but for another sibling components the initial state is just fetched, and can't see updated values. There isn't api for keeping the state. Data value used to be saved in local storage, but it has limitation, so I need to keep data inside redux state

Redux file:

 const annotationSlice = createSlice({
      name: 'annotation',
      initialState: {
        localAnnData: []
        },
      reducers: {
         updateLocalAnn: (state, { payload }) => {
           state.localAnnData = payload
           }
        }

   });
  export const { updateLocalAnn } = annotationSlice.actions;
  export const annotationSelector = (state) => state.annotation;
  export default annotationSlice.reducer;

Parent component

  ....
  /* loop through each columns of reportData  */
  const formattedColumns = column.map(
    ({
      Header,
      Key,
      fieldType /* 'STRING', 'FLOAT' etc */,
      dataType,
      format /* align: left */,
      LinkThrough /* consisting of reportid, parameters and rules passed */,
      Annotations /* Annotataion object in the column */,
      CustomActions,
    }) => {
      const isDataTypeArray = dataType?.toLowerCase() === 'array';
      if (Annotations) {
        const pickListValues = Annotations.value;
        const params = Annotations.parameters;
        return {
          Header,
          accessor: Key,
          toolbarLabel: Header,
          width: 250,
          sortable: false,
          canSort: false,
          disableSortBy: false,
          defaultCanSort: false,
          Cell: (props) =>
            child({
              ...props,
              reportId,
              paramsValues,
              pickListValues,
              params,
              viewAnnotationModal,
              saveAnnotation,
              allColumn:
                column /* each column entries passed as allColumn; 
              reportData.columns */,
              label: Annotations.label,
              objType: Annotations.obj_type,
              data,
              // updateLocalAnnData: updateLocalAnnotationData,
              // localAnnData,
            }),
        };
      }
 

Child component which is called in a loop:

      export const child = (props) => {
        
                const dispatch = useDispatch();
                const { localAnnData } = useSelector(annotationSelector);
          
        
          const {
          row,
          params  ,
          value,
          reportId,
          column,
           paramsValues  ,
           viewAnnotationModal  ,
          pickListValues  
          allColumn  
          label,
          objType,
          updateMyAnnData,
          data,
         } = props;
        
                const setUpdatedValue = (field, val) => {
                   let annoData = localAnnData; 
                   annoData = annoData?.length ? annoData : data;
                   annoData = annoData.map((el) =>
                   el.Titan_BE_ID === row.original.Titan_BE_ID
                    ? { ...el, [field]: val } : el,
                 );
                dispatch(updateLocalAnnData(annoData));
         
          }; 
          const onChange = (e) => {
            setUpdatedValue(column.id, e.target.value);
          };
                  
         return (
            <div style={{ display: 'flex' }}>
               {!pickListValues && (<div>
                  <CustomTextBox
                    param={{
                      name: column.id,
                      value: values,
                    }}
                    
                    onHandleChange={onChange}
                    isAnnotationTextbox
                    placeholderText='Enter Comments'/>
                </div>)}
                { pickListValues?.length > 0 && (<div>
                  <customDropDown
                    param={{
                      name: column.id,
                      values: pickListValues,
                    }}
                    onHandleChange={onChange}/>
                </div>)}
               .......;
        };

Updating the state is working for the first component , but the second child component doesn't have access to it, and it just shows the default value. Is there something wrong in my design?

Thanks

mary
  • 369
  • 1
  • 5
  • 16
  • first of all, in your `saveAnnotation` function you have to call `updateLocalAnn` in the `dispatch` . `dispatch(updateLocalAnn())` – KeyvanKh Mar 28 '22 at 07:12
  • Thanks @KeyvanKh, It was typo during typing the code in this site. There is no error in saving/updating the states in my code. – mary Mar 28 '22 at 10:40
  • Are you *calling* that `child` as a function instead of using it as a component with `JSX`? Can you show how you render that? – phry Mar 28 '22 at 10:53
  • 1
    Also, right now you are dispatching `undefined` as `action.payload` so you will just set `localData` to `undefined`. Is that intended? – phry Mar 28 '22 at 10:54
  • I have updated my sample now, That is part of parent and child component – mary Mar 28 '22 at 19:43
  • localAnnData is updated correctly with an array of data in child component. but everyTime new child component is rendered via parent component, useSelector doesn't show the latest/updated localAnnData , it is an empty array. – mary Mar 28 '22 at 19:54
  • in `annotationSelector = (state) => state.annotation` there is no `annotation` in your store. did you meant `annotationSelector = (state) => state.localAnnData` – KeyvanKh Mar 29 '22 at 06:45
  • Based on https://redux-toolkit.js.org/usage/usage-guide , I think selector should point to the name of slice – mary Mar 29 '22 at 10:57
  • The first time that I changed the value of dropdown, and called setUpdatedValue successfully, the value of redux's state(localAnnData) is updated. After that, I clicked on another dropdown in the second row, localAnnData.length is equal zero.and it doesn't have the latest updated value. However, it works fine while changing textbox's values in each table's row – mary Mar 29 '22 at 11:15
  • Don't know why I gave negative point while I updated the post with all the code? My question was about sharing the state between siblings, and maybe didn't need all code – mary Mar 30 '22 at 21:50

1 Answers1

0

Finally , I could figure out what was the problem in my code. First,I monitored prevState, action, nextState in redux/toolkit via wrapping App component with PersistGate, after that I noticed that prevState is replaced by action.payload, and old values in the array is removed. I have changed the reducer function based on prevState and action.payload (state parameter) and updated prevState based on the values passed in payload. I had to move some logic into reducer for making up new state:

    updateLocalAnnData: (state, { payload }) => {
     const prevState= [...state.localAnnData];
     const keepData = (prevState.length > 0) ? prevState.map(data =>  
       data.Titan_BE_ID === payload.data.Titan_BE_ID  ? {...data, 
       [payload.field]: payload.val} : data 
      
  ) : payload.allData.map(data =>  
    data.Titan_BE_ID === payload.data.Titan_BE_ID  ? {...data, [payload.field]: payload.val} : data 
   
   );
  state.localAnnData = [ ...keepData]
},
mary
  • 369
  • 1
  • 5
  • 16