Reputation: 43
So I am working on this UserData App (for practicing purposes). I have one component where I store hardcoded user data - an array with different user objects. In my app, I want a list of users (which displays usernames only) on the left side of the screen, and a panel on the right that displays all the details about the user that I selected in the list. (Check out the screenshot.) I'm importing the data to my functional parent component, AppContainer.js, where I'm using the state hook to store the selected user id in state = 'selectedUserId'. I give it a value of null for the first render so that it says 'select a user' before I've clicked on anyone. In my handleClick function, I want to update the userId with every click etc. In my App.js component, I want to map through the data and render the ul with the different li elements as well as the panel. Somewhere along the way, I made a mistake - when I click on a user, a type error is thrown and the console says 'handleClick is not a function'. Any ideas why? Here is a list to my sandbox if you're interested: https://codesandbox.io/s/user-data-app-with-prop-types-tkphx?file=/src/AppContainer.js:0-571
This is UserData.js :
export const USERS_DATA = [{
id: 1,
user_name: "jwrefford0",
first_name: "Jozef",
last_name: "Wrefford",
occupation: "Editor",
catch_phrase: "repurpose next-generation schemas"
}]
This is AppContainer.js :
import React from 'react';
import ReactDOM from 'react-dom';
import { App } from './App';
import { useState } from "react";
import { USERS_DATA } from "./UserData";
export default function AppContainer() {
const [selectedUserId, setSelectedUserId] = useState(null);
const handleClick = (newUserId) => {
setSelectedUserId(newUserId)
};
const selectedUserObj = USERS_DATA.find(
(element) => element.id === selectedUserId
);
return (
<App selectedUserId={selectedUserId} handleClick={handleClick}
selectedUserObj={selectedUserObj} />
)
}
And finally App.js :
import "./styles.css";
import { USERS_DATA } from "./UserData";
export default function App(props) {
const selectedUserObj = props.selectedUserObj;
const handleClick = props.handleClick;
return (
<div className="App">
<div className="list">
<ul>
{USERS_DATA.map((user) => (
<li onClick={() => handleClick(user.id)} key={user.id}>
{user.user_name}
</li>
))}
</ul>
</div>
<div className="panel">
<p>{selectedUserObj ? `${selectedUserObj.first_name} ${selectedUserObj.last_name}
- ${selectedUserObj.occupation}` : 'Select a user'}</p>
<p>{selectedUserObj ? `${selectedUserObj.catch_phrase}` : '' }</p>
</div>
</div>
);
}
This is what it looks like: Screenshot_UserData_App
The point of this task is to learn how to use different components to simplify the functionality of each component, and also to do a prop types check - which I haven't done yet. I find it hard to grasp how to split up the logic of my app into two components - when I created the app all in one component, it worked fine. Upon splitting it up, I created a mess. Can someone enlighten me about this? Thank you!!!
Upvotes: 4
Views: 102
Reputation: 1160
I tried to open your project with codesandbox link you attached and it totally fell down. The answer is quite simple - you are importing App in curly braces while it is exported by default.
import { App } from './App'; //get rid of curly braces
The rest work fine, maybe you have already solved the problem?
The one extra thing I'd share with you - when you pass handle function like this
<li onClick={() => handleClick(user.id)} key={user.id}>
{user.user_name}
</li>
you make React to create special function for each single person. So finally you have a lot of functions in memory which are pretty same but just having different id. It is better to store id in your list item and just pass the id into your handling function through event which will be handled by the one function catchin the clicks of the whole list (in )
function handleClick(e) {
setActive(+e.target.dataset.id) // "+" here converts string value from data to number
}
...
<ul onClick={handleClick}>
{USERS_DATA.map((user) => (
<li data-id={user.id} key={user.id}>
{user.user_name}
</li>
))}
</ul>
This will work because click on the target "li" will be catched by it's parent component "ul". Now you have just one light function. Hope you will find this helpful.
Upvotes: 1