Redux State in Component

2019-06-22 17:01发布

问题:

trying to figure out how to pull Redux store state into my component from Redux. I've got mapStateToProps and "connect" wired up. However, when I click my button in "App" component, this.props doesn't have my Redux values in it.

// React and Redux Const
const { Component } = React;
const { render } = ReactDOM;
const { Provider, connect } = ReactRedux;
const {createStore, combineReducers, bindActionCreators } = Redux;



function tweetReducer(state=[],action) {
    if(action.type === 'ADD_TWEET') {
        return state.concat({ id: Date.now(), tweet: action.payload})
    } else {
        return state;
    }
}

const rootReducer = combineReducers ({
    state: (state = {}) => state,
    tweets: tweetReducer
});


class App extends Component{
    buttonClicked() {
        store.dispatch({type: 'ADD_TWEET', payload: 'This is my first 
tweet!'});
        console.log(this.props)
    }
    render() {
        return (
            <div>
                <h5>Hello from App</h5>
                <button onClick={this.buttonClicked.bind(this)}>Button</button>

                <div>-------------------</div>
                <Display />
            </div>
         )
     }
}

class Display extends Component {
    render() {
        return (
            <div>
                <h3>Tweets:</h3>
                {this.props.tweets}
            </div>
        )
    }
}

function mapStateToProps(state) {
    console.log('mapping state to props')

    return {
        tweets: state.tweets
    }
}

let store = createStore(rootReducer)

render (
    <Provider store={store}>
        <App />
    </Provider>
    , document.querySelector('#app')
);
connect(mapStateToProps)(App)

console.log(store.getState());

回答1:

Looks like you've got a couple issues there.

First, it helps to understand that connect()(MyComponent) returns a new component that "wraps" around your "real" component. In your example, you're calling connect() after you've rendered <App />, and you aren't actually saving and using the component generated by connect(). What you need is something like:

let store = createStore(rootReducer)

const ConnectedApp = connect(mapStateToProps)(App);

render(
    <Provider store={store}>
        <ConnectedApp />
    </Provider>
, document.querySelector('#app')
);

Second, part of the point of connecting a component is that it shouldn't actually reference the store directly. connect() can take a second parameter, known as mapDispatchToProps. If you don't supply a mapDispatch parameter, it will automatically give your component this.props.dispatch. So, your App component should look like this to start with:

class App extends Component{
    buttonClicked(){
        this.props.dispatch({type: 'ADD_TWEET', payload: 'This is my first tweet!'});
        console.log(this.props)
    }

That should be enough to get the App component receiving data from Redux and dispatching actions.



回答2:

This is how you should proceed with getting store state in your component.

1) Create reducers folder and create a new file index.js

/* reducers/index.js */

import { combineReducers } from "redux";
import tweetReducer from "./tweetReducer";

const rootReducer = combineReducers({
    tweets: tweetReducer
});

export default rootReducer;

/* reducers/tweetReducer.js */

function tweetReducer(state=[],action) {
    switch(action.type) {
        case 'ADD_TWEET': 
            return state.concat({ id: Date.now(), tweet: action.payload});
        default:
            return state;
    }
}

/* components/App.js */

import React, { Component } from 'react';
import { connect } from 'react-redux';
class App extends Component {
    buttonClicked() {
        this.props.store.dispatch({type: 'ADD_TWEET', payload: 'This is my first 
tweet!'});
        console.log(this.props)
    } 
    render() {
        return (
            <div>
                <h5>Hello from App</h5>
                <button onClick={this.buttonClicked.bind(this)}>Button</button>

                <div>-------------------</div>
                <Display />
            </div>
         )
     }
}
function mapStateToProps(state) {
   console.log('mapping state to props')
   return {
     tweets: state.tweets
   }
}
export default connect(mapStateToProps)(App);

/* components/Display.js */

import React, { Component } from 'react';
  export default class Display extends Component {
     render() {
        return (
            <div>
               <h3>Tweets:</h3>
               {this.props.tweets}
             </div>
        )
     }
  }

/*Main.js */

import React, { Component } from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import { store } from "./store";

render(
    <Provider store={store}>
        <App store={store} />
    </Provider>,
    document.querySelector('#app')
);

/* store/index.js */

import { createStore, applyMiddleware, compose } from "redux";
import reducers from "../reducers";

const store = createStore(
    reducers,
    composeEnhancers(applyMiddleware())
);

export { store };