programing

리듀서에서 저장소가 변경되면 useSelector가 업데이트되지 않습니다.React JS 리덕스

kakaobank 2023. 3. 28. 22:04
반응형

리듀서에서 저장소가 변경되면 useSelector가 업데이트되지 않습니다.React JS 리덕스

나는 환원기로 상태를 바꾸고 있다.디버깅 시 상태가 실제로 변경되었음을 확인하였습니다.하지만 컴포넌트가 업데이트되지 않습니다.

컴포넌트:

function Cliente(props) {
    const dispatch = useDispatch()
    const cliente = useSelector(({ erpCliente }) => erpCliente.cliente)
    const { form, handleChange, setForm } = useForm(null)

...

function searchCepChangeFields() {
    //This call the action and change the store on reducer
    dispatch(Actions.searchCep(form.Cep))  
        .then(() => {   
            // This function is only taking values ​​from the old state. 
            // The useSelector hook is not updating with store
            setForm(form => _.setIn({...form}, 'Endereco', cliente.data.Endereco))
            setForm(form => _.setIn({...form}, 'Uf', cliente.data.Uf))
            setForm(form => _.setIn({...form}, 'Cidade', cliente.data.Cidade))
            setForm(form => _.setIn({...form}, 'Bairro', cliente.data.Bairro))                  
        })
}

리듀서:

 case Actions.SEARCH_CEP:
        {
            return {
                ...state,
                data: { 
                    ...state.data,
                    Endereco: action.payload.logradouro,
                    Bairro: action.payload.bairro,
                    UF: action.payload.uf,
                    Cidade: action.payload.cidade                    
                }
            };
        }  

주의: redux-toolkit을 사용하여 코드 참조를 방지하는 것이 좋습니다.redux를 사용하기 위해서는 더 좋고 거의 필수적인 방법입니다.

여러분이 마주하는 문제는 물체를 다룰 때 매우 흔하고, 여러분이 물체의 속성을 바꾸고 있기 때문에 소품은 변하지 않지만, 물체 자체는 반응 측에서 변하지 않습니다.

참조가 그대로 유지되기 때문에 완전히 새로운 오브젝트 반응에서도 속성 오브젝트가 변경되지 않습니다.

다음과 같이 새 참조를 작성해야 합니다.

Object.assign(state.data,data);

return {
  ...state,
  data: { 
    ...state.data,
    Endereco: action.payload.logradouro,
    Bairro: action.payload.bairro,
    UF: action.payload.uf,
    Cidade: action.payload.cidade                    
  }
}

이 문제를 해결하는 Immer 라이브러리에 대해 자세히 알아보십시오.

할 필요는 없다

Object.assign(state.data, data);

어레이 또는 객체의 데이터를 변경할 때 항상 사용 가능

return(
  object: {...state.object, a: 1, b: 2},
  array: [...state.array, 1, 2, 3]
)

이 3개의 점(...)는 반드시 새로운 오브젝트를 만듭니다.redex에서는 상태를 갱신할 뿐만 아니라 항상 새 개체를 생성해야 합니다.이렇게 하면 redux는 데이터가 변경되었음을 확인할 수 없습니다.

오브젝트 또는 어레이를 네스트하는 경우에도 마찬가지입니다.

다음 사항에 주의해 주십시오.

initialState = {
 object: {
     ...object,
     anotherObject:{
        ...anotherObject,
        a: 1,
        b: 2
      }
   }
}

어떤 이유에서인지 Object.assgin은 ES6 구문을 사용한 업데이트를 인식하지 않습니다.

updatedConnectors = state.connectors

그러면 현재 상태에 대한 참조가 생성됩니다.ES6에서는 ...을 도입하여 새로운 기준을 만듭니다.

updatedConnectors = { ...state.connectors }
.....
return  {
    ...state,
    connectors: updatedConnectors
};

이를 사용하여 새 참조를 추출하고 복사합니다.그것 또한 상태 변화를 유발합니다.

업데이트 9월 27일/20일 이 문제를 처리하기 위해 몇 가지 유틸리티 함수를 작성했습니다.해봅시다.

//Utils
export const getStateSection = ({ state, sectionName }) => {

  const updatedState = { ...state }
  const updatedSection = updatedState[sectionName]
  return updatedSection
}

export const mergeUpdatedSection = ({ state, sectionName, updatedValue }) => {
  const updatedState = { ...state }
  updatedState[sectionName] = updatedValue
  return updatedState
}

그런 다음 모든 환원제에서 다음과 같이 사용해야 합니다.

//reducer
const initState = {
  scheduleDetail: null,
  timeSlots: null,
  planDetail: {
    timeSlots: [],
    modifedTimeSlots: [],
    id: 0
  }

}
.....  
const handlePickTimeSlot = (state, action) => {
  let planDetail = getStateSection({ state, sectionName: 'planDetail' })
  // do stuff update section
  return mergeUpdatedSection({ state, sectionName: 'planDetail', updatedValue: planDetail })
}

정교한 BA 편집 큐가 꽉 차서.

여기서 받아들여지는 대답은 데이터가 거기에 있다는 것이 그가 의미한 것이다.

case MYCASE:
  let newDataObject = Object.assign(state.data, {...action.payload});
  // or 
  // let newDataObject = Object.assign(state.data, {key: 'value', 'key2': 'value2' ...otherPropertiesObject);
  return {
    ...state,
    ...newDataObject
  }

스토어를 작성하는 파일을 수정할 때 발생할 수 있는 흥미로운 엣지 케이스가 있습니다.

레독스 스토어가 있는 파일이Provider컴포넌트(일반적으로 App.tsx)는 React의 핫 모듈 새로고침(HMR)에 의해 새로고침되지 않지만 리덕스 스토어 파일이 변경되어 HMR에 의해 새로고침되고 새로운 스토어가 생성되어 스토어가 생성됩니다.Provider는 실제로 redux 스토어의 오래된 인스턴스를 에 전달할 수 있습니다.

글에 과 같은 .setup-store.ts 삭제:

/**
 * Note! When making changes to this file in development, perform a hard refresh. This is because
 * when changes to this file are made, the react hot module reloading will re-run this file, as
 * expected. But, this causes the store object to be re-initialized. HMR only reloads files that
 * have changed, so the Store Provider in App.tsx *will not* be reloaded. That means useSelector
 * values will be querying THE WRONG STORE.
 */

문제가 아닙니다. 리액트가 어떻게 작동하는지 이해해야 합니다.예상되는 동작입니다.

이 경우 호출하고 있습니다.

dispatch(dispatch(「」) searchCep(이하 「)」)를 참조해 주세요. Cep)
( ( ) { .. } 、 = > { ...★★★★★★★★★★★★...}

그러나 이 모든 작업은 하나의 렌더링에서 수행되며 변경된 저장소는 다음 렌더링에서만 수행됩니다. ★★★★★★★★★★★★★★★.then값이 업데이트된 다음 렌더에서가 아니라 첫 번째 렌더에서 소품을 가져옵니다.예를 들어 다음과 같습니다.

import React from 'react';
import { useSelector, useDispatch } from "react-redux";
import { selectCount, incrementAsync } from "./redux";
import "./styles.css";

export default function App() {
  const value = useSelector(selectCount);
  const dispatch = useDispatch();

  const incrementThen = () => {
    console.log("value before dispatch", value);
    dispatch(incrementAsync(1)).then(() =>
      console.log("value inside then", value)
    );
  };

  console.log("render: value", value);

  return (
    <div className="App">
      <p>{value}</p>
      <button onClick={incrementThen}>incrementThen</button>
    </div>
  );
}

출력

value before dispatch 9
render: value 10
value inside then 9

언급URL : https://stackoverflow.com/questions/58850699/useselector-not-updating-when-store-has-changed-in-reducer-reactjs-redux

반응형