简体   繁体   English

React-Redux state 更改后重新渲染

[英]React-Redux re-rendering after state changed

I'm trying to understand React+Redux.我正在尝试理解 React+Redux。 So, now I'm trying to fetch data from API, and faced with popular problem: when I change Redux state, it does not refresh my container component.所以,现在我试图从 API 获取数据,并面临一个流行的问题:当我更改 Redux state 时,它不会刷新我的容器组件。
I read several questions here, most common problems are mutating state, and incorrect connect usage.我在这里阅读了几个问题,最常见的问题是变异 state 和不正确的connect使用。 I checked my code, everything looks fine.我检查了我的代码,一切看起来都很好。 I suppose, that problem is in Reqct hook useState , in which I call my action generator.我想,这个问题出在 Reqct 钩子useState中,我在其中调用了我的动作生成器。
Code:代码:
Action generator动作发生器

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"));
  }
}

Reducer减速器


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
    }
}

Container component容器组件

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

And finally, part of my React-component code.最后,我的部分 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

Looks really strange, like magic)看起来很奇怪,像魔术一样)
Maybe, I do something wrong with useEffect , not with Redux?也许,我做错了useEffect ,而不是 Redux? I need to make this request when my component renders, and re-render it with received data.我需要在我的组件呈现时发出此请求,并使用接收到的数据重新呈现它。

Just change const [accounts, setAccounts] = useState(props.acnList);只需更改const [accounts, setAccounts] = useState(props.acnList);

to const accounts = props.acnList;const accounts = props.acnList;

Learn more on this blog post .在此博客文章中了解更多信息。

You need to do it to all props that change.您需要对所有更改的道具进行此操作。

Edit编辑

Long story short:长话短说:

This is a common mistake of copying the props into state.这是将道具复制到 state 中的常见错误。

Because props change over time and you need to update the state to reflect the props change (so many unecessary re-renders).因为道具会随着时间而变化,您需要更新 state 以反映道具变化(如此多的不必要的重新渲染)。 The best is to use props directly.最好是直接使用道具。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM