简体   繁体   中英

React-Router-Dom <Link> not render page

I'm building a practice app that uses Unsplash to render users photos. I'm using React and Redux. With react-router-dom , I'm trying to follow the docs but I find it very confusing to set up. Here's what I have so far. When I click on a result out of a returned list of results from a search, I want it to render a user page profile.

index.js (make sure I have react-router-do set up correctly):

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import './index.css';
import App from './App';
// import store from './app/store';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import reducers from "./app/reducers/rootReducer"; 
import * as serviceWorker from './serviceWorker';

const storeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(reducers, storeEnhancers(applyMiddleware(thunk)));

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

Top component App


import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import Images from "./app/components/Images";
import Search from "./app/components/Search";
import UserProfile from "./app/components/UserProfile";

import "./App.css";

function App() {
  return (
    <>
      <Search />
      <Images />
      <Router>
        <Route link="/userProfile">
          <UserProfile />
        </Route>
      </Router>
    </>
  );
}

export default App;

search (parent component to searchResults where exists):

import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { queryAction } from "../actions/queryAction";
import SearchResults from "./SearchResults";

const Search = (props) => {
  const [query, setQuery] = useState("");
  console.log(props.searches);

  const searchPhotos = async (e) => {
    e.preventDefault();
    console.log("submitting form");
    props.queryAction(query);
  };

  const showUsers = (user, e) => {
        e.preventDefault()
       console.log(user)
  
  };

  return (
    <>
      <form className="form" onSubmit={searchPhotos}>
        <label className="label" htmlFor="query">
          {" "}
        </label>
        <input
          type="text"
          name="query"
          className="input"
          placeholder={`Try "dog" or "apple"`}
          value={query}
          onChange={(e) => setQuery(e.target.value)}
        />
        <button type="submit" className="button">
          Search
        </button>
      </form>

      <SearchResults results={props.searches} showUsers={showUsers} />
    </>
  );
};

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

const mapDispatchToProps = (dispatch) => {
  return {
    queryAction: (entry) => dispatch(queryAction(entry)),
  };
};

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

searchResults :

import React from "react";
import { BrowserRouter as Router, Link } from "react-router-dom";
import { getUserAction } from "../actions/getUserAction";
import { connect } from "react-redux";


const SearchResults = (props) => {
  const { results } = props.results.searches;

  const handleClick = (result, e) => {
    e.preventDefault();
    props.getUser(result.username);
  };
  return (
    <>
      {results &&
        results.map((result, id) => {
          return (
            <div key={id}>
              <Router>
                <Link to="/userProfile" onClick={(e) => handleClick(result, e)}>
                  {result.username}
                </Link>
              </Router>
            </div>
          );
        })}
    </>
  );
};

const mapDispatchToProps = (dispatch) => {
  return {
    getUser: (query) => dispatch(getUserAction(query)),
  };
};

export default connect(null, mapDispatchToProps)(SearchResults);

and finally the UserProfile component:

import React from 'react';
import { connect } from 'react-redux';

const UserProfile = props => {
  
   console.log(props)
    return (
        <div>
        
        </div>
    );
}

const mapStateToProps = state => {
    return {
        user: state.users 
    }
}

export default connect(mapStateToProps, null)(UserProfile);

app component

import React from "react";
import { Switch, Route } from "react-router-dom";
import Images from "./app/components/Images";
import Search from "./app/components/Search";
import UserProfile from "./app/components/UserProfile";

import "./App.css";

function App() {
  return (
    <>
      <Search />
      <Images />
      <Switch>  
        <Route path="/userProfile/:username">
          <UserProfile />
        </Route>
      </Switch>
    </>
  );
}

export default App;

SearchResults component

import React from "react";
import { Link } from "react-router-dom";

const SearchResults = (props) => {
  const { results } = props.results.searches;

  const handleClick = (result, e) => {
    e.preventDefault();
    props.getUser(result.username);
  };
  return (
    <>
      {results &&
        results.map((result, id) => {
          return (
            <div key={id}>
                <Link to={`/userProfile/${result.username}`}>
                  {result.username}
                </Link>
            </div>
          );
        })}
    </>
  );
};


export default SearchResults;

UserProfile component

import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { getUserAction } from "../actions/getUserAction";

const UserProfile = props => {
  
   useEffect(() => {
      props.getUserAction(props.match.params.username)
   },[])

   console.log(props)
    return (
        <div>
          {props.user
            ? <div>{user.username}</div>
            : <div>Loading...</div>
          }
        </div>
    );
}

const mapStateToProps = state => {
    return {
        user: state.users 
    }
}

const mapDispatchToProps = (dispatch) => {
  return {
    getUser: (query) => dispatch(getUserAction(query)),
  };
};
export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);

Edit: Add a param to your link and remove the onclick. Update the Route to expect a :username param. You can access the param through props in UserProfile component.

Make sure to perform the action or access state when mounting the UserProfile component so you have some data when it renders.

Edit 2: Added UserProfile component to answer. You want to dispatch your action when the component is mounting. Also, set a ternary to show "Loading..." if state.user isn't done being fetched.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM