本文最后更新于 2024年12月20日 下午
eat-n-split(和朋友吃饭a钱的程序)
(一)实现页面及功能
页面:
功能:
1.添加新朋友(点击Add或者Close按钮均会关闭添加朋友的组件)。
2.选择一位朋友与ta分账(只需要输入总花费和我花费的,朋友的花费会自动计算),选择付款人(我和被选择的朋友两种选择),点击Split bill按钮即可把这个结果累加到原本欠的钱,同时分账界面关闭。
【解释】因为Sarah原本欠我30,这次我花费30,她帮我付了,所以我们俩扯平了。
(二)实现代码及分析
用到的组件:
App是导出的父组件
FriendList是显示朋友列表的部分(篮框)
Friend是FriendList的子组件(紫框)
FormAddFriend是添加新朋友的组件(绿框)
FormSplitBill是用于分账的组件(红框)
Button组件在多个组件中均有应用
重构后分成多个文件进行分析
(1)App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| import { useState } from "react"; import { FriendsList } from "./FriendsList"; import { FormAddFriend } from "./FormAddFriend"; import { FormSplitBill } from "./FormSplitBill"; import { Button } from "./Button";
const initialFriends = [ { id: 118836, name: "Clark", image: "https://i.pravatar.cc/48?u=118836", balance: -7, }, { id: 933372, name: "Sarah", image: "https://i.pravatar.cc/48?u=933372", balance: 20, }, { id: 499476, name: "Anthony", image: "https://i.pravatar.cc/48?u=499476", balance: 0, }, ];
export default function App() { const [showAddFriend, setShowAddFriend] = useState(false); const [friends, setFriends] = useState(initialFriends); const [selectedFriend, setSelectedFriend] = useState(null);
function handleShowAddFriend() { setShowAddFriend((show) => !show); }
function handleAddFriend(friend) { setFriends((friends) => [...friends, friend]); setShowAddFriend(false); }
function handleSelection(friend) { setSelectedFriend((cur) => (cur?.id === friend.id ? null : friend)); setShowAddFriend(false); }
function handleSplitBill(value) { setFriends((friends) => friends.map((friend) => friend.id === selectedFriend.id ? { ...friend, balance: friend.balance + value } : friend ) );
setSelectedFriend(null); }
return ( <div className="app"> <div className="sidebar"> <FriendsList friends={friends} onSelection={handleSelection} selectedFriend={selectedFriend} />
{showAddFriend && <FormAddFriend onAddFriend={handleAddFriend} />}
<Button onClick={handleShowAddFriend}> {showAddFriend ? "Close" : "Add friend"} </Button> </div>
{selectedFriend && ( <FormSplitBill selectedFriend={selectedFriend} onSplitBill={handleSplitBill} /> )} </div> ); }
|
解释
1 2 3 4 5 6 7 8
| export function Button({ children, onClick }) { return ( <button className="button" onClick={onClick}> {children} </button> ); }
|
解释
(3)FriendList.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import { Friend } from "./Friend";
export function FriendsList({ friends, onSelection, selectedFriend }) { return ( <ul> {friends.map((friend) => ( <Friend friend={friend} key={friend.id} onSelection={onSelection} selectedFriend={selectedFriend} /> ))} </ul> ); }
|
解释
(4)Friend.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import { Button } from "./Button";
export function Friend({ friend, onSelection, selectedFriend }) { const isSelected = selectedFriend?.id === friend.id;
return ( <li className={isSelected ? "selected" : ""}> <img src={friend.image} alt={friend.name} /> <h3>{friend.name}</h3>
{friend.balance < 0 && ( <p className="red"> You owe {friend.name} ${Math.abs(friend.balance)} </p> )} {friend.balance > 0 && ( <p className="green"> {friend.name} owes you ${Math.abs(friend.balance)} </p> )} {friend.balance === 0 && <p>You and {friend.name} are even</p>}
<Button onClick={() => onSelection(friend)}> {isSelected ? "Close" : "Select"} </Button> </li> ); }
|
解释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import { useState } from "react"; import { Button } from "./Button";
export function FormAddFriend({ onAddFriend }) { const [name, setName] = useState(""); const [image, setImage] = useState("https://i.pravatar.cc/48");
function handleSubmit(e) { e.preventDefault();
if (!name || !image) return;
const id = crypto.randomUUID(); const newFriend = { id, name, image: `${image}?u=${id}`, balance: 0, }; onAddFriend(newFriend);
setName(""); setImage("https://i.pravatar.cc/48"); }
return ( <form className="form-add-friend" onSubmit={handleSubmit}> <lable>🧑🤝🧑 Friend name</lable> <input type="text" value={name} onChange={(e) => setName(e.target.value)} />
<lable>🐻 Image URL</lable> <input type="text" value={image} onChange={(e) => setImage(e.target.value)} /> <Button>Add</Button> </form> ); }
|
解释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| import { useState } from "react"; import { Button } from "./Button";
export function FormSplitBill({ selectedFriend, onSplitBill }) { const [bill, setBill] = useState(""); const [paidByUser, setPaidByUser] = useState(""); const paidByFriend = bill ? bill - paidByUser : ""; const [whoispaying, setWhoIsPaying] = useState("user");
function handleSubmit(e) { e.preventDefault(); onSplitBill(whoispaying === "user" ? paidByFriend : -paidByUser); }
return ( <form className="form-split-bill" onSubmit={handleSubmit}> <h2>Split a bill with {selectedFriend.name}</h2>
<lable>💵Bill value</lable> <input type="text" value={bill} onChange={(e) => setBill(Number(e.target.value))} />
<lable>🐶Your expense</lable> <input type="text" value={paidByUser} onChange={(e) => setPaidByUser( Number(e.target.value) > bill ? paidByUser : Number(e.target.value) ) } />
<lable>🐱{selectedFriend.name}'s expense</lable> <input type="text" disabled value={paidByFriend} />
<lable>🤑Who is paying the bill</lable> <select value={whoispaying} onChange={(e) => setWhoIsPaying(e.target.value)} > <option value="user">You</option> <option value="friend">{selectedFriend.name}</option> </select> <Button>Split bill</Button> </form> ); }
|
解释