React组件间共享goodData状态问题求助(含同/跨文件场景)
问题分析与解决方案
你的代码里有两个关键错误导致use-between没生效:
- use-between用法错误:它需要传入自定义Hook,而不是组件本身。你把
AddProduct组件传给了useBetween,完全不符合API要求。 - ActionBox组件props接收错误:React组件的props是单个对象参数,你写成了多个独立参数,导致无法正确获取传入的值。
同一文件下的修复方案
先把状态逻辑抽成自定义Hook,再用use-between共享:
import React, { useState, useEffect } from 'react' import {IoMdAdd, IoIosListBox} from 'react-icons/io' import {MdClear} from 'react-icons/md' import {AiOutlineMinusSquare} from 'react-icons/ai' import {AiFillCloseCircle} from 'react-icons/ai' import {useBetween} from 'use-between' import { goods } from '../dataArray' // 1. 抽离共享状态到自定义Hook const useGoodDataHook = () => { const [presentDate, setPresentDate] = useState('') const [goodData, setGoodData] = useState({modDate: '',product: '', quantity: '', unitPrice: '', totPrice: ''}) const [dropStockList, setDropStockList] = useState(true) const [stock, setStock] = useState([]) const [shop, setShop] = useState([]) const [display, setDisplay] = useState(true) const [actionBtn, setActionBtn] = useState(true) useEffect(()=>{ let date = new Date() let day = date.getUTCDay() let month = date.getUTCMonth() let year = date.getUTCFullYear() let newDate = day+'/'+month+'/'+year setPresentDate(newDate) let list; if (localStorage.getItem('shopDB') !== null) { list = JSON.parse(localStorage.getItem('shopDB')).warehouse setStock(list) } },[]) function handleNewStock(data) { let shopDB; if (localStorage.getItem('shopDB') !== null) { shopDB = JSON.parse(localStorage.getItem('shopDB')) shopDB.warehouse.push(data) } else { shopDB = { warehouse: [data] } } localStorage.setItem('shopDB', JSON.stringify(shopDB)) } function handleChange(e) { let name = e.target.name let value = e.target.value setGoodData({...goodData, [name]:value}) } function handleSubmit(e) { e.preventDefault() if (goodData.product && goodData.quantity && goodData.unitPrice ) { const newGoodData = { ...goodData, totPrice: goodData.quantity * goodData.unitPrice, modDate: presentDate } setStock([...stock, newGoodData]) handleNewStock(newGoodData) setGoodData({modDate: '', product:'', quantity: '', totPrice: '', unitPrice: ''}) } else { // highlight unfilled field } } function handleCheck() { setDisplay(!display) } function handleStockList() { setDropStockList(!dropStockList) } return { presentDate, goodData, setGoodData, dropStockList, stock, display, actionBtn, handleChange, handleSubmit, handleCheck, handleStockList } } // 2. 用use-between包装自定义Hook,创建共享状态Hook const useSharedState = () => useBetween(useGoodDataHook) const AddProduct = () => { // 3. 在组件中使用共享状态 const { presentDate, goodData, dropStockList, stock, display, actionBtn, handleChange, handleSubmit, handleCheck, handleStockList } = useSharedState() function handleBlurClose() { // setDisplay(false) } return ( <> {display && <section className="add-stock-cont" > <div className="addition" onBlur={handleBlurClose}> <div className="nav"> <section className="title"> <h2>Add New Product</h2> </section> <span id="close-icon" onClick={handleCheck}> <AiFillCloseCircle /> </span> </div> {display && <form className="add-area"> <section className="top"> <section className = "product form-group" > <label htmlFor = "product" > Product </label> <input type = "text" name = "product" id = "product" placeholder = 'Semovita...' onChange = { handleChange } value = { goodData.product }/> </section> <section className = "quantity form-group" > <label htmlFor = "quantity" > Quantity </label> <input type = "number" name = "quantity" id = "quantity" placeholder = '0' onChange = { handleChange } value = { goodData.quantity }/> </section> <section className = "unitPrice form-group" > <label htmlFor = "unitPrice" > Unit Price </label> <input type = "number" name = "unitPrice" id = "unitPrice" placeholder = '0' onChange = { handleChange } value = { goodData.unitPrice }/> </section> <article className="totPrice"> <h4>{goodData.totPrice}</h4> </article> </section> <section className="buttons"> {actionBtn &&<button className="unClear-btn add-btn" type='submit' onClick={handleSubmit}> <span id='icon'><IoMdAdd /> </span> Add </button>} {!actionBtn && <button className="warning-color unClear-btn" id="update-btn">Update</button>} <button className="unClear-btn clear-btn"><span id="icon"><MdClear /> </span> Clear</button> {!actionBtn && <button className="unClear-btn " id="delete-btn">Delete</button>} </section> </form>} <section className="stock-list"> <div className="menu-bar" onClick={handleStockList}> {dropStockList ? <span id="icon"><AiOutlineMinusSquare /> </span> : <span id="icon"><IoIosListBox/> </span> } </div> {dropStockList && <section className="table-holder"> <table> <thead> <tr> <th>Date Mod.</th> <th>Product</th> <th>Quantity</th> <th>Unit Price</th> <th>Total Price</th> <th>Actions</th> </tr> </thead> <tbody> {stock.map((data, index)=>{ const {product, quantity, unitPrice, totPrice, modDate} = data return( <tr key={index}> <td>{modDate}</td> <td>{product}</td> <td>{quantity}</td> <td>{unitPrice}</td> <td>{totPrice}</td> <td><ActionBox index={index} product={data.product} quantity={data.quantity} unitPrice={data.unitPrice} totPrice={data.totPrice}/> </td> </tr> ) })} </tbody> </table> </section> } </section> </div> </section>} </> ) } const ActionBox = ({index, unitPrice, product, quantity, totPrice})=>{ const [dropDown, setDropDown] = useState(false) // 4. 在子组件中获取共享状态 const {goodData} = useSharedState(); function handleEdit() { console.log(index); console.log('printing...', goodData); let shopDB; if (localStorage.getItem('shopDB') !== null) { shopDB = JSON.parse(localStorage.getItem('shopDB')).warehouse console.log('the necessary info',shopDB.at(index)); } else { console.log('You are on your own lol...'); } } return( <button className="unClear-btn" onClick={handleEdit}> action </button> ) } export default AddProduct
不同文件下的实现方式
把共享状态Hook单独放在一个文件里,比如src/hooks/useSharedGoodData.js:
import { useState, useEffect } from 'react' import {useBetween} from 'use-between' const useGoodDataHook = () => { const [presentDate, setPresentDate] = useState('') const [goodData, setGoodData] = useState({modDate: '',product: '', quantity: '', unitPrice: '', totPrice: ''}) const [dropStockList, setDropStockList] = useState(true) const [stock, setStock] = useState([]) const [shop, setShop] = useState([]) const [display, setDisplay] = useState(true) const [actionBtn, setActionBtn] = useState(true) useEffect(()=>{ let date = new Date() let day = date.getUTCDay() let month = date.getUTCMonth() let year = date.getUTCFullYear() let newDate = day+'/'+month+'/'+year setPresentDate(newDate) let list; if (localStorage.getItem('shopDB') !== null) { list = JSON.parse(localStorage.getItem('shopDB')).warehouse setStock(list) } },[]) function handleNewStock(data) { let shopDB; if (localStorage.getItem('shopDB') !== null) { shopDB = JSON.parse(localStorage.getItem('shopDB')) shopDB.warehouse.push(data) } else { shopDB = { warehouse: [data] } } localStorage.setItem('shopDB', JSON.stringify(shopDB)) } function handleChange(e) { let name = e.target.name let value = e.target.value setGoodData({...goodData, [name]:value}) } function handleSubmit(e) { e.preventDefault() if (goodData.product && goodData.quantity && goodData.unitPrice ) { const newGoodData = { ...goodData, totPrice: goodData.quantity * goodData.unitPrice, modDate: presentDate } setStock([...stock, newGoodData]) handleNewStock(newGoodData) setGoodData({modDate: '', product:'', quantity: '', totPrice: '', unitPrice: ''}) } else { // highlight unfilled field } } function handleCheck() { setDisplay(!display) } function handleStockList() { setDropStockList(!dropStockList) } return { presentDate, goodData, setGoodData, dropStockList, stock, display, actionBtn, handleChange, handleSubmit, handleCheck, handleStockList } } export const useSharedState = () => useBetween(useGoodDataHook)
然后在AddProduct.jsx里导入:
import { useSharedState } from './hooks/useSharedGoodData' // ... 其他导入 const AddProduct = () => { const { ... } = useSharedState() // 组件逻辑不变 }
在ActionBox.jsx里单独导出并导入:
import { useState } from 'react' import { useSharedState } from './hooks/useSharedGoodData' const ActionBox = ({index, unitPrice, product, quantity, totPrice})=>{ const [dropDown, setDropDown] = useState(false) const {goodData} = useSharedState(); function handleEdit() { // ... 逻辑不变 } return( <button className="unClear-btn" onClick={handleEdit}> action </button> ) } export default ActionBox
内容的提问来源于stack exchange,提问作者Ireugbu David
相关产品推荐
相关产品推荐

