React Redux: Uncaught Invariant Violation (Objects are not valid as a React child)

Deadly 提交于 2019-12-13 02:53:56

问题


The error I'm receiving is "react-dom.development.js:55 Uncaught Invariant Violation: Objects are not valid as a React child (found: object with keys {counter}). If you meant to render a collection of children, use an array instead."

It occurs when I change Counter.js from <p>{this.state.counter}</p> to <p>{this.props.counter}</p>

From my understanding, I'm using the mapStateToProps and mapDispatchToProps and I should be able to pull at least the initialState of the counter, which is 0.

I'm not sure if this is the cause of the issue, but I'm using console.log to view what the state looks like, but not sure if that is correct:

{counter: {…}}
  counter: {counter: 0}
  __proto__: Object

Counter.js

// Imports: Dependencies
import React, { Component } from 'react';
import { connect } from 'react-redux';

// Imports: Action Types
import { INCREASE_COUNTER, DECREASE_COUNTER } from '../actionTypes/index';

// Component: Counter
class Counter extends React.Component {
  constructor(props) {
    super(props);

  this.state = {
    counter: 0,
  };
}

render() {
  return (
    <div>
      <h2>React Redux Counter</h2>
      <button type="button" onClick={() => this.props.increaseCounter()}>Increase</button>
      <p>{this.props.counter}</p>
      <button type="button" onClick={() => this.props.decreaseCounter()}>Decrease</button>
    </div>
  );
 }
}

// Map State To Props (Reducers)
const mapStateToProps = (state) => {
  console.log('State:');
  console.log(state);
  console.log('');

  return {
    counter: state.counter,
  };
};

// Map Dispatch To Props (Actions)
const mapDispatchToProps = (dispatch) => {
  return {
    increaseCounter: () => dispatch({ type: INCREASE_COUNTER }),
    decreaseCounter: () => dispatch({ type: DECREASE_COUNTER }),
  };
};

// Exports
export default connect(mapStateToProps, mapDispatchToProps)(Counter);

App.js

// Imports: Dependencies
import React, { Component } from 'react';

// Imports: Components
import Counter from './components/Counter';

// React Application
class App extends Component {
  render() {
    return (
      <div>
        <Counter />
      </div>
    );
  }
}

// Exports
export default App;

index.js

// Imports: Dependencies
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store/store';

// Imports: React Application
import App from './App';

// Render App
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('app'),
);

store.js

// Imports: Dependencies
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { createLogger } from 'redux-logger';

// Imports: Redux
import rootReducer from '../reducers/index';

// Redux: Thunk (Async/Await)
const middleware = [thunk];
if (process.env.NODE_ENV !== 'production') {
  middleware.push(createLogger());
}

// Redux: Store
const store = createStore(
  rootReducer,
  applyMiddleware(...middleware),
);

// Exports
export default store;

counterReducer.js

import { INCREASE_COUNTER, DECREASE_COUNTER } from '../actionTypes/actionTypes';

// Initial State
const initialState = {
  counter: 0,
};

// Redux: Counter Reducer
const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case INCREASE_COUNTER: {
      return {
        ...state,
        counter: state.counter + 1,
      };
    }
    case DECREASE_COUNTER: {
      return {
        ...state,
        counter: state.counter - 1,
      };
    }
    default: {
      return state;
    }
  }
};

// Exports
export default counterReducer;

actionTypes.js

export const INCREASE_COUNTER = 'INCREASE_COUNTER';

export const DECREASE_COUNTER = 'DECREASE_COUNTER';

回答1:


Your state is structured like this:

{
    counter: {
        counter : 0
    }
}

It's structured this way because your counterReducer defines a nested field called counter, and the counterReducer is then combined into a larger object because it's passed to combineReducers({counter : counterReducer}).

In your component, you're rendering:

<p>{this.props.counter}</p>

But, props.counter is going to be an object, like {counter : 0}.

React won't let you just plop an object into the render output - it doesn't know what to do with it.

If you just want to show the counter value, then it needs to be:

<p>{this.props.counter.counter}</p>

Another option would be to change your mapStateToProps to be:

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

The third option would be to change the counterReducer so that it only tracks the number itself as the reducer's state argument, rather than nesting that value in an object.



来源:https://stackoverflow.com/questions/54894612/react-redux-uncaught-invariant-violation-objects-are-not-valid-as-a-react-chil

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!