【问题标题】:React-redux component is not re-rendering after state changeReact-redux 组件在状态更改后不会重新渲染
【发布时间】:2020-09-29 16:30:10
【问题描述】:

我的一个 react-redux 组件在状态更改后没有重新渲染。我希望在选中复选框后启用选择。但这不会发生。只有当我在另一个触发重新渲染的组件上单击页面上的其他位置时,一切都会按我的预期进行。我究竟做错了什么?如果有任何帮助,我将不胜感激。

class Select extends React.Component {
    constructor(props) {
        super(props);
    }

render() {
    return (
        <div>
            <input type="checkbox" onClick={this.props.toggleSelect}/>
            <select disabled={ !Object.keys(this.props.syncObjects).includes("select") }>
            // some options 
            </select>
        </div>
    )
}
}

const mapDispatchToProps = {
    toggleSelect
}

const mapStateToProps = state => {
    return {
        syncObjects: state.json.objects
    }
}

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

// reducer file
const initialState = {
    objects: {}
}

export const myReducer = (state = initialState, action) => {
    switch (action.type) {
        case TOGGLE_SELECT:
            if (Object.keys(state.objects).includes("select")){
                const new_state = {...state}
                delete new_state.objects["select"]
                return new_state
            }
            else {
                return {
                    ...state,
                    objects: {
                        ...state.objects,
                        'select': ''
                    }
                }
            }

        default:
            return state
    }
}

// actions.js
export function toggleSelect() {
    return {
        type: TOGGLE_SELECT
    }
}

【问题讨论】:

  • 问题是你的reducer正在改变状态,你不应该这样做并且导致这个问题。你的 new_state 只是一个浅拷贝,然后你改变它的一个子对象。
  • 首先,您似乎没有在您的mapDispatchToProps()分派任何东西,接下来,您使用delete 运算符来改变你的商店,这是为 Redux 静默完成的,因此 React 不会触发重新渲染。请考虑使用不可变技术来过滤掉对象中的属性。
  • 我正要开始回答以说明如何解决这个问题,但后来我注意到还有一些奇怪的地方:您的 mapStateToProps 引用 state.json.objectsrender 方法关心它是否包含select 键与否,但您的减速器仅在 state.objects 内操作该键。哪个是正确的?
  • @yevgengorbunkov 我相信将mapDispatchToProps 定义为对象将自动调度相关操作,因此该部分看起来不错。你对突变当然是正确的。
  • @Helen :显然,您的问题是由使用 delete 运算符引起的

标签: javascript reactjs redux react-redux


【解决方案1】:

最好不要改变 state.updates,你可以这样做:

const objects = { ...state.objects };
if (objects.select) {
  delete objects.select;
} else {
  objects.select = true; //set it truthy
}
return {
  ...state,
  objects,
};

工作示例:

const { Provider, connect } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const initialState = {
  objects: {},
};
//action types
const TOGGLE_SELECT = 'TOGGLE_SELECT';
// actions.js
function toggleSelect() {
  return {
    type: TOGGLE_SELECT,
  };
}

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case TOGGLE_SELECT:
      const objects = { ...state.objects };
      if (objects.select) {
        delete objects.select;
      } else {
        objects.select = true; //set it truthy
      }
      return {
        ...state,
        objects,
      };
    default:
      return state;
  }
};

//creating store with redux dev tools
const composeEnhancers =
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
  reducer,
  initialState,
  composeEnhancers(
    applyMiddleware(() => (next) => (action) =>
      next(action)
    )
  )
);

class Select extends React.Component {
  render() {
    return (
      <div>
        <input
          type="checkbox"
          onClick={this.props.toggleSelect}
          checked={Object.keys(
            this.props.syncObjects
          ).includes('select')}
        />
        <div>
          select enabled:
          {String(
            Object.keys(this.props.syncObjects).includes(
              'select'
            )
          )}
        </div>
        <div>
          select enabled (simpler example):
          {String(Boolean(this.props.syncObjects.select))}
        </div>
      </div>
    );
  }
}

const mapDispatchToProps = {
  toggleSelect,
};

const mapStateToProps = (state) => {
  return {
    syncObjects: state.objects,
  };
};

const App = connect(
  mapStateToProps,
  mapDispatchToProps
)(Select);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<div id="root"></div>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-12
    • 2020-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多