#reactjs #redux #react-router-dom
#reactjs #redux #react-router-dom
Вопрос:
Я создаю практическое приложение, которое использует Unsplash для рендеринга фотографий пользователей. Я использую React и Redux. С react-router-dom
помощью, я пытаюсь следовать документам, но я нахожу это очень запутанным в настройке. Вот что у меня есть до сих пор. Когда я нажимаю на результат из возвращаемого списка результатов поиска, я хочу, чтобы он отображал профиль страницы пользователя.
index.js (убедитесь, что я все react-router-do
настроил правильно):
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")
);
Верхний компонент 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
(родительский компонент searchResults
там, где он существует):
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 amp;amp;
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);
и, наконец UserProfile
, компонент:
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);
Комментарии:
1. Как только вы обернете свой компонент с помощью BrowserRouter, вам не нужно делать это снова. Я думаю, вы хотели вместо этого обернуть свои маршруты в компоненте приложения компонентом Switch.
Ответ №1:
компонент приложения
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
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 amp;amp;
results.map((result, id) => {
return (
<div key={id}>
<Link to={`/userProfile/${result.username}`}>
{result.username}
</Link>
</div>
);
})}
</>
);
};
export default SearchResults;
Компонент пользовательского профиля
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);
Редактировать: добавьте параметр к вашей ссылке и удалите onclick. Обновите маршрут, чтобы ожидать параметр:username . Вы можете получить доступ к параметру через props в компоненте UserProfile.
Обязательно выполните действие или состояние доступа при монтировании компонента UserProfile, чтобы у вас были некоторые данные при его визуализации.
Редактировать 2: добавлен компонент UserProfile для ответа. Вы хотите отправить свое действие, когда компонент монтируется. Кроме того, установите троичный параметр, чтобы показывать «Загрузка …», если извлечение state.user не завершено.
Комментарии:
1. Когда я нажимаю на результат, все еще не ссылаюсь на новую страницу (/ userProfile). Ничего не происходит. Я попытался повторить
yarn start
. Есть идеи? Есть ли какое-то отношение к тому, что это ссылки для кликов?2. Да, ссылка не имеет onclick. Вместо этого вы можете передать параметр запроса, такой как идентификатор результата. Затем внутри вашего компонента userProfile
mapStateToProps
извлеките нужный объект / пользователя, используя идентификатор.3. Не могли бы вы рассказать о том, как это будет выглядеть?
4. Я отредактировал ссылку и фрагмент маршрута выше, чтобы использовать параметры. Кроме того, вот пример из документации о том, как получить доступ к параметрам запроса reactrouter.com/web/api/Route/component
5. Извините, все еще не понимаю. Все, что я вижу в этих документах
component={}
, но нет способа получить доступ к хранилищу redux в<Link>