Ре-рендеринг React-Redux после изменения состояния - PullRequest
0 голосов
/ 10 апреля 2020

Я пытаюсь понять React + Redux. Итак, теперь я пытаюсь получить данные из API и столкнулся с популярной проблемой: когда я изменяю состояние Redux, он не обновляет sh моего компонента контейнера.
Я прочитал несколько вопросов здесь, наиболее распространенные проблемы - это состояние мутации и неправильное использование connect. Я проверил свой код, все выглядит хорошо. Я полагаю, что проблема заключается в ловушке Reqct useState, в которой я называю мой генератор действий.
Код:
Генератор действия

export const requestAccounts = () => ({
  type: 'REQUEST_ACCOUNTS'
});

export const receivedAccounts = (data) => ({
  type: 'RECEIVED_ACCOUNTS',
  data
});

export const requestAccountsError = (errText) => ({
  type: 'RECEIVED_ACCOUNTS_ERROR',
  errText
});

export function getAccounts(clientRef = 1) {

  return async function (dispatch) {
    async function fetchData() {
      let res;
      try {
        res = await fetch("https://wstest.grant.ua/stubs/accnts.json", { //добавить парамтер "номер клиента"
            method: 'GET' // *GET, POST, PUT, DELETE, etc.
        });
        if (res.ok) {
          let resJson = await res.json();
          dispatch(receivedAccounts(resJson.acn_list));
        }
        else {
          dispatch(requestAccountsError('Error during accounts request! Status '+res.status));
        }

      }
      catch (err) {
        dispatch(requestAccountsError(err.message));
      };   
    }
    dispatch(requestAccounts());
    await fetchData();
    /*I supposed that my problem depends on async loading, 
      so I tried to comment all above code and uncomment row below - also, 
      React did not re-render my component...*/
    //dispatch(requestAccountsError("ERROR_MESSAGEEEE"));
  }
}

Редуктор


const initialState = {
    isFetching : false,
    isError : false,
    errorText : "",
    accounts : []
}

export function acnList(state = initialState, action) {
    switch (action.type) {
      case "RECEIVED_ACCOUNTS":
        return Object.assign({}, state, {
            isFetching: false, 
            isError: false, 
            errorText: "", 
            accounts: action.acnList
          })
/*I tried to write return { errorText: "123" } - also no re-render.. So, problem is not in 
mutating previous state*/
      case "RECEIVED_ACCOUNTS_ERROR":          
        return Object.assign({}, state, {
            isFetching: false, 
            isError: true,
            errorText: "ERRTEXTTTT",
            accounts: []
        })
      case "REQUEST_ACCOUNTS":
        return Object.assign({}, state, {
            isFetching: true, 
            isError: false,
            errorText: "",
            accounts: []
        })
      default:
        return state
    }
}

Компонент контейнера

import { connect } from 'react-redux'
import AcnListComponent from '../../MainMenuComponents/AcnListComponent'
import {getAccounts} from '../actions/actions'

const mapStateToProps = (state, ownProps) => {
  return {
    acnList: state.acnList.accounts,
    isError: state.acnList.isError,
    isFetching: state.acnList.isFetching,
    errorText : state.acnList.errorText
  }
}

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    getAccounts: () => {
      dispatch(getAccounts())
    }
  }
}

const AcnListContainer = connect(
  mapStateToProps,
  mapDispatchToProps
)(AcnListComponent)

export default AcnListContainer

И, наконец, часть моего кода компонента React.

//imports

function AcnListComponent(props) {

  /*here I can see that props are changed sucessfully (according to state). But no re-render!*/
  console.log(props);
  const {t} = props;

  const [isLoading, setIsLoading] = useState(props.isFetching);
  const [accounts, setAccounts] = useState(props.acnList);
  const [emptyMessage, setEmptyMessage] = useState(props.errorText);
  const [isError, setIsError] = useState(props.isError);

  useEffect(() => {
    if ((accounts.length === 0) && !isError) {
        props.getAccounts();
    }
  }, []); //I need to call this effect only once, when component renders
//renders

выглядит действительно странно, как волхвы c)
Может быть, я что-то не так делаю с useEffect, а не с Redux? Мне нужно сделать этот запрос, когда мой компонент рендерится, и повторно сделать его с полученными данными.

1 Ответ

2 голосов
/ 10 апреля 2020

Просто измените const [accounts, setAccounts] = useState(props.acnList);

на const accounts = props.acnList;

Подробнее об этом сообщении в блоге .

Вам нужно сделать это для всех изменяются реквизиты.

Редактировать

Короче говоря:

Это распространенная ошибка при копировании реквизита в состояние.

Потому что реквизиты меняются со временем, и вам нужно обновить состояние, чтобы отразить изменение реквизита (так много ненужных повторных рендеров). Лучше всего использовать реквизит напрямую.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...