【问题标题】:React Redux Store updating, but component not re-renderingReact Redux Store 更新,但组件不重新渲染
【发布时间】:2017-06-17 06:44:08
【问题描述】:

使用终端测试我发送的操作,Redux-logger 显示我的状态正在正确更新。但是,由于状态更改,我的组件不会重新渲染。我查看了关于组件不重新渲染的 SO 答案,大多数回复声称状态正在发生变化;因此,Redux 不会重新渲染。但是,我正在使用 Lodash 的合并来对对象进行深度复制,我很确定我没有返回修改后的对象。 (请看下面附上的sn-p)

很想听听你们的一些建议,把我的头发拉出来!

const usersReducer = (state = {}, action) => {
  Object.freeze(state); // avoid mutating state

  console.log(state); 
  // returns an empty object  
  let newState = merge({}, state);
  console.log(newState); 
  // returns my state with my dispatched action object inside  already???
  // newState for some reason already has new dispatched action
  switch (action.type) {
    case RECEIVE_USER:
      let newUser = {[action.user.id] = action.user};
      return merge(newUser, newUser);
    case RECEIVE_USERS:
      newState = {};
      action.users.forEach(user => {
        newState[user.id] = user;
      });
      return merge({}, newState);
    default:
      return state;
  }
};

反应容器组件

import { connect } from 'react-redux';
import { receiveUsers, receiveUser, refreshAll, requestUsers, requestUser } from '../../actions/user_actions';
import allUsers from '../../reducers/selectors';
import UserList from './user_list';

const mapStateToProps = (state) => ({
  users: allUsers(state), // allUsers (selector that takes the state specfically the user Object and returns an array of user Objects)
  state
});

const mapDispatchToProps = (dispatch) => ({
  requestUser: () => dispatch(requestUser()),
  requestUsers: () => dispatch(requestUsers()),
  receiveUsers: (users) => dispatch(receiveUsers(users)),
  receiveUser: (user) => dispatch(receiveUser(user)),
  refreshAll: (users) => dispatch(refreshAll(users))
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(UserList);

React 展示组件

import React from 'react';

class UserList extends React.Component {
  render() {
    const { users, state } = this.props;

    const userItems = users.map((user, idx) => {
        return(<li key={idx}>{user.username}</li>);
    });

    return (
      <div>
        <ul>
          { userItems }
        </ul>
      </div>
    );
  }
}

export default UserList;

反应商店

import { createStore, applyMiddleware } from 'redux';
import createLogger from 'redux-logger';
import RootReducer from '../reducers/root_reducer';

const logger = createLogger();
const configureStore = (preloadedState = {}) => {
  return createStore(
    RootReducer, 
    preloadedState,
    applyMiddleware(logger));
};

// const configureStore = createStore(rootReducer, applyMiddleware(logger));

// oddly enough, when I have the store as a constant and not a function that returns the store constant, dispatching actions through the terminal will correctly update the state and rerender the component 

export default configureStore;

反应选择器

const allUsers = ({ users }) => {
  return Object.keys(users).map(id => (
    users[id]
  ));
};

export default allUsers;

【问题讨论】:

  • 你能添加你的组件代码吗?将组件连接到商店的方式可能存在问题。
  • 这可能与您的问题无关,但是您对合并的任何使用对我来说都没有任何意义。您到底希望完成什么?我建议您只使用 splats,例如return {...state, x: 42}
  • 在哪里添加usersReducer 到商店?您能否验证您的组件 mapStateToProps 在商店状态更改时是否被调用?如果不是,则可能意味着您的减速器未正确执行。
  • @Mustafa 在我的 RootReducer 我调用 CombineReducers({ users: usersReducer });我认为您正在做某事,似乎没有调用 mapStateToProps,但是当您调度操作时不会自动调用它吗?
  • @Tonyhliu 也许是因为您没有在应用程序的任何地方调用 configureStore .. 我还没有看到商店是这样创建的,所以不确定它是否可能。这个return merge(newUser, newUser); 对我来说也没有意义。

标签: reactjs redux render react-redux


【解决方案1】:

我花了很多时间发现当使用超过 1 个 reducer(使用 combineReducers)时,您的 mapStateToProps 应该指向正确的 reducer 名称,例如

const mapStateToProps = state => ({
  someVar: state.yourReducerName.someVar,
  loading: state.yourReducerName.loading,
  error: state.yourReducerName.error
});

【讨论】:

    【解决方案2】:

    从 prop 状态创建新的数组副本以重新渲染组件

    render() {
    
    const {allPost} = this.props;
    //Use the spread operator to create a new copy of the array
    const posts = [...allPost];
    
     const plansList = () => {
         return posts.length < 1 ? null : posts && <PlansList allPost={posts} 
       />;
     };
    
    return (
      <>
        <Container className="mt-lg-5 pt-lg-5">
        {plansList()}
      </Container>
      </>
    );
    }
    

    【讨论】:

      【解决方案3】:

      这种情况下的常见问题是使用非反应性操作来更改状态。例如对数组使用 concat(),而不是 push() 等等。

      【讨论】:

      • 谢谢!这对我来说是一个很大的痛苦!使用推送不会更新状态。使用扩展运算符const x = [...x, y] 或使用 concat....
      【解决方案4】:

      我遇到了类似的问题,以防万一有人偶然发现,我需要克隆数组以便重新渲染视图:

      export const addFieldRow = () => (
          (dispatch: any, getState: any) => {
              const state = getState();
              const myArrayOfObjects = myArrayOfObjectsProp(state);
              const newObject = {
                  key: "",
                  value: "",
              };
              myArrayOfObjects.push(newObject);
              dispatch(addFieldRowAction({ myArrayOfObjects: [...myArrayOfObjects] })); <== here
          }
      );
      

      【讨论】:

      【解决方案5】:

      我使用这个解决方案来做到这一点。 我将用户置于我的状态,并使用 componentWillReceiveProps 在任何更改时对其进行更新。希望它有所帮助:-)

      class UserList extends React.Component {
          constructor(props) {
             super(props);
             console.log(this.props);
             this.state = {
                users: props.users
             };
          }
          componentWillReceiveProps(nextProps) {
              if (this.props.users !== nextProps.users) {
                  this.setState({
                      users: nextProps.users,
                  });
              }
          }
      
        render() {
          const { users } = this.state;
      
          const userItems = users.map((user, idx) => {
              return(<li key={idx}>{user.username}</li>);
          });
      
          return (
            <div>
              <ul>
                { userItems }
              </ul>
            </div>
          );
        }
      }
      
      export default UserList;
      

      【讨论】:

      • componentWillReceiveProps 是 React v16 中基于类/容器组件的不安全方法
      • 这个问题是关于 Redux 的,你的解决方案没有以任何方式包含它。
      【解决方案6】:

      你的 React 组件是什么样的?您是在其中使用内部状态还是使用道具来下推数据。通常我看到问题在于人们使用 Redux 状态设置道具的内部状态。您应该将道具下推到组件,它们将在更新时重新渲染。

      另外,请查看 https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en

      看看道具是不是真的变了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-06-15
        • 2018-10-15
        • 1970-01-01
        • 1970-01-01
        • 2017-07-22
        • 2018-03-24
        • 1970-01-01
        • 2023-03-28
        相关资源
        最近更新 更多