Currently, I am trying to pass a specific piece of data, the user’s name
, from one functional component, the <User/>
component, to another, the <Profile />
component, when the user navigates to a certain page.
Here is my code:
User.js
import React from 'react'; import { connect } from 'react-redux'; import { Link } from 'react-router-dom'; import { withRouter } from 'react-router-dom'; function User(props) { return ( <div> <Link to={`/${props.username}`}> <hr /> <p> ({props.name}) {props.username} </p> </Link> </div> ) } const mapStateToProps = state => ({}); export default connect(mapStateToProps)(withRouter(User));
UsersList.js
import React from 'react'; import { withRouter } from 'react-router-dom'; import User from './User'; function UsersList() { return ( <div> <h1>Users</h1> <User username="john_smith" name="John Smith"/> <User username="james_madison" name="James Madison"/> <User username="george_washington" name="George Washington"/> </div> ); } export default (withRouter(UsersList));
Feed.js
import React from "react"; import { Container } from "react-bootstrap"; import UsersList from "./users/UsersList"; function Feed() { return ( <div> <Container> <UsersList/> </Container> </div> ); } export default Home;
App.js
import React from "react"; import { Route, Switch } from "react-router-dom"; import Feed from './components/Feed'; import Profile from "./components/Profile"; import Root from "./Root"; function App() { return ( <Root> <Switch> <Route exact path="/" component={Feed} /> <Route exact path="/:username" component={Profile} /> </Switch> </Root> ); } export default App;
And here is the current <Profile />
page – I simply want to pass the user’s name, not the username, into a pair of <h1></h1>
tags:
Profile.js
import React from "react"; import { Container } from "react-bootstrap"; function Profile(props) { return ( <Container> <h1>I SIMPLY WANT TO PASS THE USERS NAME HERE</h1> </Container> ); } export default Profile;
I appreciate any help or direction!
Advertisement
Answer
You have to use Redux. This is how I sloved it-
First install redux module: npm install react-redux
src/components/Profile.js
Map the user data which is in redux store using mapStateToProps function
import React from "react"; import { Container } from "react-bootstrap"; import { connect } from 'react-redux'; function Profile( props) { let users = props.users let userName = window.location.pathname.substring(1); var name; users.forEach((element) => { if(element['username'] === userName){ name = element['name']; } }); return ( <Container> <h1>I SIMPLY WANT TO PASS THE USERS NAME HERE</h1> {name } </Container> ); } const mapStateToProps = state => ({ users: state.users, }); export default connect(mapStateToProps)(Profile);
/src/action.js
Here I have initialized all the user initial values, ideally the user data you will get from another system, in such case you will use Thunk or Saga for side effect operations
export const LOAD_USER = 'LOAD_USER'; const users = [{ username:'john_smith', name: 'John Smith' }, { username:'james_madison', name: 'James Madison' }, {username:'george_washington', name: 'George Washington'}]; export const loadeUser = () => ({ type: LOAD_USER, payload: { users }, });
/src/reducer.js
I am simply passing all the user data to the state object
import { LOAD_USER } from './actions'; export const users = (state = [], action) => { const { type, payload } = action; switch (type) { case LOAD_USER :{ const { users } = payload; return users; } default: return state; } }
/src/components/User.js
import React from 'react'; import { Link } from 'react-router-dom'; function User({user}) { return ( <div> <Link to={`/${user.username}`}> <hr /> <p> ({user.name}) {user.username} </p> </Link> </div> ) } export default User;
/src/components/UsersList.js
Here we have to use both mapDispatchToProps and mapStateToProps so that dispatch action is executed on a load of the component via useEffect hook.
import React, { useEffect } from 'react'; import { withRouter } from 'react-router-dom'; import { loadeUser } from '../actions'; import { connect } from 'react-redux'; import User from './User'; function UsersList({ users = [] , startLoadingUsers}) { useEffect(() => { startLoadingUsers(); }, []); return ( <div> <h1>Users</h1> { users.map(user => <User user={user} />) } </div> ); } const mapStateToProps = state => ({ users: state.users, }); const mapDispatchToProps = dispatch => ({ startLoadingUsers: () => dispatch(loadeUser()), }); export default connect(mapStateToProps, mapDispatchToProps) (withRouter(UsersList));
/src/App.js
Use the BrowserRouter to wrap around the different routes
import React from "react"; import { Route, Switch,BrowserRouter as Router, } from "react-router-dom"; import Feed from './components/Feed'; import Profile from "./components/Profile"; function App() { return ( <Router> <Switch> <Route exact path="/" component={Feed} /> <Route exact path="/:username" component={Profile} /> </Switch> </Router> ); } export default App;
/src/index.js
Finally, hook the store as a wrapper around App component so that all the components can use Redux store and that is done by Provider.
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import { Provider } from 'react-redux'; import { configureStore } from './store'; const store = configureStore(); ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') );
/src/store.js
import { createStore, combineReducers } from 'redux'; import { users } from './reducer'; const reducers = { users, }; const rootReducer = combineReducers(reducers); export const configureStore = () => createStore( rootReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(), );
And the final result