0

I'm building a web app using React Redux and React Router. In my app I have a component called Listings, where the user can use a search bar to filter for certain types of listings. Everything works perfectly as long as the user is not on the listings page. But when the user tries to use the search bar from the listings page as opposed to the home page, the component doesn't re-render. I kinda get why this is happening as the DOM isn't changing, but have yet to figure out a workaround.

I also get this warning "react_devtools_backend.js:4026 Warning: Hash history cannot PUSH the same path; a new entry will not be added to the history stack"

Below is the relevant code in the search component

    handleSubmit(e) {
        e.preventDefault;
        const searchUrl = new URLSearchParams(this.state).toString();
        this.props.history.push({
            pathname: `/listings/`,
            key: Math.random(),
            search: `${searchUrl}`
        })
    }

And here is some of the code in my Listings component

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

        this.state = {listings: props.listings};
    }

    componentDidMount() {
        this.props.indexListings();
    }

    componentDidUpdate(prevProps) {
        if (this.props.listings != prevProps.listings) {
            if (this.props.history.location.search) {
                const queryString = require('query-string');
                const parsed = queryString.parse(this.props.location.search);
                const listings = [...this.props.listings];
                this.setState({listings: listings.filter(listing => listing.city.includes(parsed.city))});
            } else {
                const listings = [...this.props.listings];
                this.setState({listings: listings});
            }
        }
    }

Listing Container Code

import { connect } from "react-redux";
import { indexListings } from "../../actions/listing_actions";
import Listings from "./Listings";

const mapStateToProps = state => ({
    listings: Object.values(state.entities.listings)
})

const mapDispatchToProps = dispatch => ({
    // this gets all the listings from the backend
    indexListings: () => dispatch(indexListings())
})

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

as well as the code in my App component

const App = () => (
    <Switch>
        <AuthRoute path="/login" component={LoginFormContainer} />
        <AuthRoute path="/signup" component={SignupFormContainer} />
        <Route path = "/listings/" component={ListingsContainer}/>
        <Route path = "/users/show/" component={UserContainer}/>
        <Route path = "/listing/new/" exact component={NewListingContainer}/>
        <Route path = "/listing/:id/" component={ShowListingContainer}/>        
        <Route path = "/" component={Splash} />
    </Switch>
);

Any advice at all or constructive feedback would be well appreciated!

Cœur
  • 37,241
  • 25
  • 195
  • 267
Harry
  • 5
  • 2
  • Checkout this out and see if it helps [stackoverflow](https://stackoverflow.com/questions/38839510/forcing-a-react-router-link-to-load-a-page-even-if-were-already-on-that-page) – Han Oct 13 '22 at 06:07
  • I think the `componentDidUpdate` logic is possibly flawed. Why is `Listings` duplicating passed props into local state? This is a React anti-pattern. Where are any props passed to the `Listings` component? Can you share a more complete [mcve]? – Drew Reese Oct 13 '22 at 06:15
  • @Drew-Reese Thanks for responding. I tried to fix the passing props directly into state, and also included the container where I pass props into Listings. I edited to include both of these changes. – Harry Oct 13 '22 at 15:59
  • @Han That seems to be exactly what I'm looking for. Will update you if it works. Thanks! – Harry Oct 13 '22 at 16:03
  • @han Unfortunately I added a random key in my history.push and the component is still not re-rendering. I also toyed with adding a random key into the listings route in the App Component but that didn't trigger a re-render either. I'm going to read through more of the React Router docs, but since I'm using Redux instead of hooks it's a bit tougher for me to understand. – Harry Oct 13 '22 at 17:27
  • Think you could stand up a *running* [codesandbox](https://codesandbox.io/) demo that reproduces the routing/rendering issue that we could inspect live? You can mock the redux props injected into the `Listings` component. – Drew Reese Oct 13 '22 at 20:20
  • 1
    @Drew-Reese I really appreciate the help Drew but I actually just figured out the issue! I thought the issue was that no methods in the component were getting called the second time around but I was wrong. You were correct that my ComponentDidUpdate logic was flawed. Upon using the search bar a second time, componentDidUpdate actually does get called but my conditional wasn't registering a change in ```props.histroy```. I've since changed if ```(this.props.listings != prevProps.listings)``` to ```(this.props != prevProps)```! Thanks to you and everyone else for helping me out. – Harry Oct 13 '22 at 23:36

1 Answers1

0

@Drew-Reese was correct that my ComponentDidUpdate logic was flawed and the issue is now resolved. I thought the issue was that no methods in the component were getting called the second time around but I was wrong. Upon using the search bar a second time (while already in the Listings Component), componentDidUpdate actually does get called but my conditional wasn't registering a change in props.histroy. I've since changed if (this.props.listings != prevProps.listings) to if (this.props != prevProps) at the top of componentDidUpdate! Thanks everyone for helping me solve this issue.

Harry
  • 5
  • 2