React跨页面组件传props遇newItems空、map报错问题求助
React状态跨组件传递与渲染问题排查
在开发React应用时,我在App组件中通过[newItems, setNewItems] = useState([])声明了状态,想把它作为props传递给其他页面组件,最终在Home页面的MoneyInOutDetails组件中遍历newItems渲染列表。目前未使用数据库,但遇到两个问题:
- 控制台显示
newItems为空 - MoneyInOutDetails组件报错“无法读取newItems的map属性”
想确认当前实现方式是否可行,以及问题出在哪里。
相关代码
MoneyIn组件
//MoneyIn Component const MoneyIn = ({newItems, setNewItems}) => { let handleSaveMonyIn = (event) => { event.preventDefault(); //setBalanceDue(balanceSet); if (totalAmountIn === 0 || itemDescription === "") { setSeverity("error") //setError(true); setMessage("Enter Amount and Item Description"); setOpen(true) } else if (totalSellingPrice > totalAmountIn) { console.log(totalSellingPrice); // setError(true); setSeverity("error") setMessage("Total Selling Prices cannot be bigger than Total amount"); setOpen(true) } else { const newMoneyInData = { totalAmountIn, amountRecieved, balanceDue, newItems, itemDescription }; setMoneyInData([...moneyInData, newMoneyInData]); localStorage.setItem("moneyIn", JSON.stringify(moneyInData)); document.getElementById("totalAndRecievedAmt").reset(); document.getElementById("itemDescriptionFrm").reset(); //setSuccess(true); setSeverity("success"); setMessage("Saved Successfully !!!"); setOpen(true); // setTotalAmountIn(0); // setAmountRecieved(0); // setBalanceDue(0); // setItemDescription(''); // setNewItems([]); console.log(newMoneyInData); } } let handleSaveItem = () => { const newItemData = { productName, sellingPriceOfTotal, quantityCount, sellingPrice }; setNewItems([...newItems, newItemData]); console.log(newItemData); } let handleSaveItemOnclick = () => { if (sellingPriceOfTotal > totalAmountIn) { console.log(totalAmountIn); console.log(sellingPrice); console.log("Alert is working"); // setError(true); setSeverity("error") setMessage("Selling Price cannot be bigger than Total"); setOpen(true) // setOpen(false) } else if (sellingPrice === 0 || productName === "") { console.log(sellingPrice); console.log(productName); setSeverity("error") //setError(true); setMessage("Product name and Selling price cannot be empty"); setOpen(true) } else { handleSaveItem() setVisible(!visible) setProductName(""); setSellingPrice(0); setQuantityCount(1); } } return ( <div> <div>Items</div> <ItemLists newItems={newItems} handleDelete={handleDelete}/> <div className='totalItemsAdded'> <p>Total</p> <p>${totalSellingPrice}</p> </div> </div> ); }
ItemLists组件
//ItemList Component const ItemLists = (props) => { const newItems = props.newItems; const handleDelete = props.handleDelete; console.log(newItems); return ( <div> {newItems.map((items) => { const { productName, sellingPriceOfTotal, quantityCount, sellingPrice } = items; return ( <> <div className='itemsAdded'> <div className='eachItemAdded'><div>{productName}</div> <div>{sellingPriceOfTotal} = {sellingPrice} x {quantityCount}</div> </div> <div className='deleteEditFont'><FontAwesomeIcon icon={faTrashCan} onClick={() => handleDelete(items)} /></div> </div> </> ); })} </div> ) } export default ItemLists
App组件
//App.js Component const App = () => { const [newItems, setNewItems] = useState([]); // localStorage.setItem("newIt", JSON.stringify(newItems)); console.log(newItems); return ( <> <Router> <Routes> <Route path='/' exact element={<Home newItems = {newItems} setNewItems={setNewItems}/>} /> <Route path='/moneyIn' element={<MoneyIn newItems = {newItems} setNewItems={setNewItems}/>} /> </Routes> </Router> </> ) } export default App
Home组件
//Home Component const Home = ({newItems, setNewItems}) => { return ( <> <div className='allBodyCards'> <Balances/> <div className='transactions'> <DailyTransactions /> <MoneyInOutDetails newItems={newItems} setNewItems={setNewItems}/> </div> </div> </> ) } export default Home
MoneyInOutDetails组件
//MoneyInOutDetails Component Where am running the map to list items in JSX const MoneyInOutDetails = ({newItems, setNewItems}) => { console.log(newItems); newItems.map((items) => { const { productName, sellingPriceOfTotal} = items; return ( <div className='moneyInOutWrapper'> <div>{productName}</div> <div className='amountAndIcons'> <div className='amountInOut'>${sellingPriceOfTotal}</div> <div className='deleteEditIcons'> <FontAwesomeIcon icon={faPenToSquare} /> <FontAwesomeIcon icon={faTrashCan} /> </div> </div> </div> ) }) } export default MoneyInOutDetails
问题原因与解决办法
1. MoneyInOutDetails组件未返回渲染结果
该组件中newItems.map()执行后没有被返回,导致组件无内容输出;同时如果newItems意外变为undefined,会直接触发“无法读取map属性”的错误。
修复代码:
const MoneyInOutDetails = ({newItems, setNewItems}) => { console.log(newItems); // 必须返回map结果,且给列表项加唯一key return (newItems || []).map((items) => { const { productName, sellingPriceOfTotal} = items; return ( <div className='moneyInOutWrapper' key={productName}> <div>{productName}</div> <div className='amountAndIcons'> <div className='amountInOut'>${sellingPriceOfTotal}</div> <div className='deleteEditIcons'> <FontAwesomeIcon icon={faPenToSquare} /> <FontAwesomeIcon icon={faTrashCan} /> </div> </div> </div> ) }) }
- 用
(newItems || [])确保即使props传递异常,也能以空数组执行map - 给每个列表项添加唯一
key属性,避免React渲染警告
2. 页面刷新导致状态丢失
当前newItems仅存在于内存状态中,页面刷新后会重置为空数组。如果需要持久化数据,可在App组件中同步到localStorage:
修改App组件:
const App = () => { // 初始化时从localStorage读取数据 const [newItems, setNewItems] = useState(() => { const saved = localStorage.getItem("newItems"); return saved ? JSON.parse(saved) : []; }); // 状态变化时自动保存到localStorage useEffect(() => { localStorage.setItem("newItems", JSON.stringify(newItems)); }, [newItems]); console.log(newItems); return ( <> <Router> <Routes> <Route path='/' exact element={<Home newItems = {newItems} setNewItems={setNewItems}/>} /> <Route path='/moneyIn' element={<MoneyIn newItems = {newItems} setNewItems={setNewItems}/>} /> </Routes> </Router> </> ) }
3. 实现方式可行性
你当前以App组件作为顶层状态容器,通过props向下传递状态的方式完全可行,是小型React应用中常用的状态管理方案。如果后续应用复杂度提升,可考虑使用Context API或Redux替代props层层传递的模式。
内容的提问来源于stack exchange,提问作者Aham_Uzoma
相关产品推荐
相关产品推荐

