Citut
Citut

Reputation: 907

How to access store in different component?

So I have a search bar where I store the queries with redux, which seems to work. I am now trying to access that query in a results component which I am going to use to display the results of the query.

I have tried using MapStateToProps and then just calling {this.props.query} in my Results component, but that doesn't get the query changes from the search bar.

Store creation:

import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import { BrowserRouter } from "react-router-dom";
import { createStore, combineReducers, applyMiddleware } from "redux";
import { userReducer } from "./redux/reducers/user-reducer";
import { searchReduer } from "./redux/reducers/search-reducer"
import logger from "redux-logger";
import { Provider } from "react-redux";

const store = createStore(
  combineReducers({
      user: userReducer,
      query: searchReducer,
  }),
  {},
  applyMiddleware(logger)
);

ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>,
  document.getElementById("root")
);

serviceWorker.unregister();

Search:

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import TextField from '@material-ui/core/TextField';
import { connect } from "react-redux";
import elasticsearchUtility from "../utilities/elastic-search-utility";

const styles = theme => ({
    container: {
        display: 'flex',
        flexWrap: 'wrap',
        justifyContent: 'center',
        flexDirection: 'row',
    },
    margin: {
        margin: theme.spacing.unit,
    },
    cssLabel: {
        color: 'white',
        '&$cssFocused': {
            color: 'white',
        },
    },
    cssFocused: {
    },
    cssUnderline: {
        color: 'white',
    },
    cssOutlinedInput: {
        '&$cssFocused $notchedOutline': {
            borderColor: 'white',
        },
    },
    notchedOutline: {
        borderWidth: '1px',
        borderColor: 'white !important'
    },
});

class Search extends Component{
    state = {
        searchQuery: ""
    };

    componentDidMount() {
        elasticsearchUtility.startClient();
    }

    onChange = event => {
        this.props.updateQuery(event.target.value);
    };

    render() {
        const {searchQuery, classes} = this.props;

        return (
            <div className={this.props.classes.container}>
                <TextField
                    fullWidth={true}
                    className={classes.margin}
                    InputLabelProps={{
                        classes: {
                            root: classes.cssLabel,
                            focused: classes.cssFocused,
                        },
                    }}
                    InputProps={{
                        classes: {
                            root: classes.cssOutlinedInput,
                            focused: classes.cssFocused,
                            notchedOutline: classes.notchedOutline,
                        },
                    }}
                    onChange={this.onChange}
                    label="Service search"
                    variant="outlined"
                    id="custom-css-outlined-input"
                    value={searchQuery}
                />
            </div>
        );
    }
}
const mapStateToProps = (state) => {
    return {
        query: state.searchQuery
    }
};

const mapDispatchToProps = (dispatch) => {
    return {
        updateQuery: (query) => {
            dispatch(search(query))
        }
    }
};

function search(value) {
    return {type: "SEARCH", value};
}

Search.propTypes = {
    classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(
    connect(
        mapStateToProps,
        mapDispatchToProps
    )(Search)
);

Search-results:

import React, {Component} from 'react';
import connect from "react-redux/es/connect/connect";

class SearchResults extends Component {

    render() {
        console.log(this.props.query);
        return (
            <div>
            <h1>Test + {this.props.query}</h1>
            </div>
        );
    }
}

function mapStateToProps(state) {
    return { query: state.searchQuery };
}

export default connect(mapStateToProps)(SearchResults)

Search-reducer:

export const initialQuery = '';

export const searchReducer = (state = initialQuery, action) => {

    switch (action.type) {
        case "SEARCH":
            return action.value;
        default:
            return state;
    }

};

In search-results, {this.props.query} is always undefined, even though I can see the state.query changing when I input text in the search bar. I am assuming I am misunderstanding something about Redux, but I'm not super sure what, since I am able to update the searchQuery properly in my "Search" component.

Upvotes: 2

Views: 217

Answers (2)

Anil Kumar
Anil Kumar

Reputation: 2309

Use :

function mapStateToProps(state) {
return { query: state.query.searchQuery };
}

Upvotes: 1

helloitsjoe
helloitsjoe

Reputation: 6529

It looks like you're mixing up query and searchQuery in a few places.

  combineReducers({
      user: userReducer,
      query: searchReducer,
  }),

You're setting state.query as your global query object, but both of your mapStateToProps are trying to access state.searchQuery.

Also, in Search's render, you have const {searchQuery, classes} = this.props;, but again, mapStateToProps is mapping state.searchQuery to props.query, so props.searchQuery is undefined.

Seems like you just have to make sure you're using the correct mapping, or pick either query or searchQuery and use it both in global state and in props.

Upvotes: 3

Related Questions