React-Redux:在 useState 初始渲染期间未读取数据
React-Redux: Data not read during initial render in useState
我正在尝试获取名为包的数据列表并将其放入 table。添加了过滤器和排序。
- 我从 pakageList reducer 获取包
- 分配给数据状态
- 然后添加排序和过滤逻辑并将数据分配给名为 filteredPackages 的变量
一切似乎都很好,但是当页面最初加载时 table 的内容是空的,即数据状态是空的。添加或删除包时会发生这种情况,渲染也会发生。
一旦我返回并再次来到这个屏幕,数据就会加载。数据存在于我从 reducer 获得的包中,但没有分配给数据状态。
任何人都可以尝试检查并让我知道可以在这里做什么。对不起,如果我的代码不好。提前致谢。
跳过不需要的代码
const PackageScreen = ({ match }) => {
const [ order, setOrder ] = useState('ASC')
const packageList = useSelector(state => state.packageList)
const { loading, error, packages } = packageList
const packageCreate = useSelector(state => state.packageCreate)
const { loading:loadingCreate , error:errorCreate , success: successCreate, package: createdPackage } = packageCreate
const packageDelete = useSelector(state => state.packageDelete)
const { loading:loadingDelete , error:errorDelete , success: successDelete } = packageDelete
const [ data, setData ] = useState([])
useEffect(() => {
dispatch({type: PACKAGE_CREATE_RESET})
if(!userInfo || !userInfo.isAdmin){
navigate('/')
}
setName('')
setMaxDays(0)
setMaxUsers(0)
dispatch(listPackages())
setData(packages)
}, [dispatch, userInfo, successCreate, successDelete, navigate] )
const sorting = (col) => {
if(order === 'ASC'){
const sorted = [...data].sort((a,b) =>
a[col].toString().toLowerCase() > b[col].toString().toLowerCase() ? 1 : -1
)
setData(sorted)
setOrder('DSC')
}
if(order === 'DSC'){
const sorted = [...data].sort((a,b) =>
a[col].toString().toLowerCase() < b[col].toString().toLowerCase() ? 1 : -1
)
setData(sorted)
setOrder('ASC')
}
}
function search(data) {
return data.filter((pack) =>
pack.packageName.toLowerCase().indexOf(q.toLowerCase()) > -1
)
}
const filteredPackages = search(data)
const submitHandler = (e) =>{
e.preventDefault()
dispatch(createPackage({
packageName: name,
maxDaysAllowed : maxDays * 30,
maxUserAllowed : maxUsers
}))
}
const deleteHandler = (id) =>{
if(window.confirm('Are you sure you want to delete?')){
dispatch(deletePackage(id))
}
}
return(
<>
<Link to='/' className='btn btn-dark my-3'>Go Back</Link>
<h1>Add Package</h1>
<Form onSubmit={submitHandler}>
<Row className='my-3' >
<Col>
<Form.Group className="mb-3" controlId='name'>
<FloatingLabel controlId="floatingInput" label="Package Name" className="mb-3">
<Form.Control type="text" placeholder="Package name"
value={name}
onChange = {(e)=> setName(e.target.value)}
/>
</FloatingLabel>
</Form.Group>
</Col>
<Col>
<Form.Group controlId='maxUsers'>
<FloatingLabel controlId="floatingSelect" label="Max. allowed users">
<Form.Control as='select' value={maxUsers}
onChange={(e) => setMaxUsers(e.target.value)}>
{/*<Form.Select aria-label="Floating label select example">*/}
<option>Select number of users</option>
<option value="3">3</option>
<option value="5">5</option>
<option value="10">10</option>
{/*</Form.Select>*/}
</Form.Control>
</FloatingLabel>
</Form.Group>
</Col>
<Col>
<Form.Group controlId='maxDays'>
<FloatingLabel controlId="floatingSelect" label="Package Limit">
<Form.Control as='select' value={maxDays}
onChange={(e) => setMaxDays(e.target.value)}>
{/*<Form.Select aria-label="Floating label select example">*/}
<option>Select Period</option>
<option value="1">1 Month</option>
<option value="3">3 Months</option>
<option value="6">6 Months</option>
<option value="12">1 year</option>
{/*</Form.Select>*/}
</Form.Control>
</FloatingLabel>
</Form.Group>
</Col>
</Row>
<Button type='submit' variant='primary'>
Save
</Button>
</Form>
<h2 className='mt-4'>Package List</h2>
<div className='d-flex'>
<div className='p-2'>
<div className='searchTable'>
<InputGroup className="me-2 my-2">
<InputGroup.Text>Search</InputGroup.Text>
<FormControl aria-label="Search"
value={q} onChange={(e) => setQ(e.target.value)}
/>
</InputGroup>
</div>
</div>
</div>
{ loading ? <Loader />
: error ? <Message variant='danger'>{error}</Message>
: (
<div>
<Table striped bordered hover responsive='md' className='table-sm bg-light' id="table-to-xls">
<thead>
<tr>
<th onClick={() => sorting('packageName')} ><span className='btn'>Package Name</span></th>
<th onClick={() => sorting('maxUserAllowed')} ><span className='btn'>Maximum Users</span></th>
<th onClick={() => sorting('maxDaysAllowed')} ><span className='btn'>Maximum Days</span></th>
<th><span className='btn'>Action</span></th>
</tr>
</thead>
<tbody>
{filteredPackages.map(pack => (
<tr key={pack._id} >
<td>{pack.packageName}</td>
<td>{pack.maxUserAllowed}</td>
<td>{pack.maxDaysAllowed}</td>
<td>
{/*<LinkContainer to={`/admin/product/${product._id}/edit`}>*/}
<Button variant='info' className='btn-sm mx-1' disabled>
<i className='fas fa-edit'></i>
</Button>
{/*</LinkContainer>*/}
<Button variant='danger' className='btn-sm'
onClick={()=> deleteHandler(pack._id)}
>
<i className='fas fa-trash'></i>
</Button>
</td>
</tr>
)) }
</tbody>
</Table>
</div>
)
}
</>
)
}
export default PackageScreen
data 和 filteredPackage 在初始渲染时都是空的。
我在 useEffect 中尝试了以下但没有成功
useEffect(() => {
dispatch({type: PACKAGE_CREATE_RESET})
if(!userInfo || !userInfo.isAdmin){
navigate('/')
}
setName('')
setMaxDays(0)
setMaxUsers(0)
dispatch(listPackages())
**const fetchData = async()=>{
await setData(packages)
}
fetchData()**
}, [dispatch, userInfo, successCreate, successDelete, navigate] )
如果您需要更多详细信息,请告诉我。
为包创建一个 const 并将其分配给您的数据状态
const packages = useSelector(state => state.packageList.packages)
...
const [ data, setData ] = useState(packages)
并编写一个 useEffect 来在您的包存储值呈现时更新您的数据状态
useEffect(()=>{
setData([...packages])
},[packages])
我正在尝试获取名为包的数据列表并将其放入 table。添加了过滤器和排序。
- 我从 pakageList reducer 获取包
- 分配给数据状态
- 然后添加排序和过滤逻辑并将数据分配给名为 filteredPackages 的变量 一切似乎都很好,但是当页面最初加载时 table 的内容是空的,即数据状态是空的。添加或删除包时会发生这种情况,渲染也会发生。 一旦我返回并再次来到这个屏幕,数据就会加载。数据存在于我从 reducer 获得的包中,但没有分配给数据状态。 任何人都可以尝试检查并让我知道可以在这里做什么。对不起,如果我的代码不好。提前致谢。
跳过不需要的代码
const PackageScreen = ({ match }) => {
const [ order, setOrder ] = useState('ASC')
const packageList = useSelector(state => state.packageList)
const { loading, error, packages } = packageList
const packageCreate = useSelector(state => state.packageCreate)
const { loading:loadingCreate , error:errorCreate , success: successCreate, package: createdPackage } = packageCreate
const packageDelete = useSelector(state => state.packageDelete)
const { loading:loadingDelete , error:errorDelete , success: successDelete } = packageDelete
const [ data, setData ] = useState([])
useEffect(() => {
dispatch({type: PACKAGE_CREATE_RESET})
if(!userInfo || !userInfo.isAdmin){
navigate('/')
}
setName('')
setMaxDays(0)
setMaxUsers(0)
dispatch(listPackages())
setData(packages)
}, [dispatch, userInfo, successCreate, successDelete, navigate] )
const sorting = (col) => {
if(order === 'ASC'){
const sorted = [...data].sort((a,b) =>
a[col].toString().toLowerCase() > b[col].toString().toLowerCase() ? 1 : -1
)
setData(sorted)
setOrder('DSC')
}
if(order === 'DSC'){
const sorted = [...data].sort((a,b) =>
a[col].toString().toLowerCase() < b[col].toString().toLowerCase() ? 1 : -1
)
setData(sorted)
setOrder('ASC')
}
}
function search(data) {
return data.filter((pack) =>
pack.packageName.toLowerCase().indexOf(q.toLowerCase()) > -1
)
}
const filteredPackages = search(data)
const submitHandler = (e) =>{
e.preventDefault()
dispatch(createPackage({
packageName: name,
maxDaysAllowed : maxDays * 30,
maxUserAllowed : maxUsers
}))
}
const deleteHandler = (id) =>{
if(window.confirm('Are you sure you want to delete?')){
dispatch(deletePackage(id))
}
}
return(
<>
<Link to='/' className='btn btn-dark my-3'>Go Back</Link>
<h1>Add Package</h1>
<Form onSubmit={submitHandler}>
<Row className='my-3' >
<Col>
<Form.Group className="mb-3" controlId='name'>
<FloatingLabel controlId="floatingInput" label="Package Name" className="mb-3">
<Form.Control type="text" placeholder="Package name"
value={name}
onChange = {(e)=> setName(e.target.value)}
/>
</FloatingLabel>
</Form.Group>
</Col>
<Col>
<Form.Group controlId='maxUsers'>
<FloatingLabel controlId="floatingSelect" label="Max. allowed users">
<Form.Control as='select' value={maxUsers}
onChange={(e) => setMaxUsers(e.target.value)}>
{/*<Form.Select aria-label="Floating label select example">*/}
<option>Select number of users</option>
<option value="3">3</option>
<option value="5">5</option>
<option value="10">10</option>
{/*</Form.Select>*/}
</Form.Control>
</FloatingLabel>
</Form.Group>
</Col>
<Col>
<Form.Group controlId='maxDays'>
<FloatingLabel controlId="floatingSelect" label="Package Limit">
<Form.Control as='select' value={maxDays}
onChange={(e) => setMaxDays(e.target.value)}>
{/*<Form.Select aria-label="Floating label select example">*/}
<option>Select Period</option>
<option value="1">1 Month</option>
<option value="3">3 Months</option>
<option value="6">6 Months</option>
<option value="12">1 year</option>
{/*</Form.Select>*/}
</Form.Control>
</FloatingLabel>
</Form.Group>
</Col>
</Row>
<Button type='submit' variant='primary'>
Save
</Button>
</Form>
<h2 className='mt-4'>Package List</h2>
<div className='d-flex'>
<div className='p-2'>
<div className='searchTable'>
<InputGroup className="me-2 my-2">
<InputGroup.Text>Search</InputGroup.Text>
<FormControl aria-label="Search"
value={q} onChange={(e) => setQ(e.target.value)}
/>
</InputGroup>
</div>
</div>
</div>
{ loading ? <Loader />
: error ? <Message variant='danger'>{error}</Message>
: (
<div>
<Table striped bordered hover responsive='md' className='table-sm bg-light' id="table-to-xls">
<thead>
<tr>
<th onClick={() => sorting('packageName')} ><span className='btn'>Package Name</span></th>
<th onClick={() => sorting('maxUserAllowed')} ><span className='btn'>Maximum Users</span></th>
<th onClick={() => sorting('maxDaysAllowed')} ><span className='btn'>Maximum Days</span></th>
<th><span className='btn'>Action</span></th>
</tr>
</thead>
<tbody>
{filteredPackages.map(pack => (
<tr key={pack._id} >
<td>{pack.packageName}</td>
<td>{pack.maxUserAllowed}</td>
<td>{pack.maxDaysAllowed}</td>
<td>
{/*<LinkContainer to={`/admin/product/${product._id}/edit`}>*/}
<Button variant='info' className='btn-sm mx-1' disabled>
<i className='fas fa-edit'></i>
</Button>
{/*</LinkContainer>*/}
<Button variant='danger' className='btn-sm'
onClick={()=> deleteHandler(pack._id)}
>
<i className='fas fa-trash'></i>
</Button>
</td>
</tr>
)) }
</tbody>
</Table>
</div>
)
}
</>
)
}
export default PackageScreen
data 和 filteredPackage 在初始渲染时都是空的。 我在 useEffect 中尝试了以下但没有成功
useEffect(() => {
dispatch({type: PACKAGE_CREATE_RESET})
if(!userInfo || !userInfo.isAdmin){
navigate('/')
}
setName('')
setMaxDays(0)
setMaxUsers(0)
dispatch(listPackages())
**const fetchData = async()=>{
await setData(packages)
}
fetchData()**
}, [dispatch, userInfo, successCreate, successDelete, navigate] )
如果您需要更多详细信息,请告诉我。
为包创建一个 const 并将其分配给您的数据状态
const packages = useSelector(state => state.packageList.packages)
...
const [ data, setData ] = useState(packages)
并编写一个 useEffect 来在您的包存储值呈现时更新您的数据状态
useEffect(()=>{
setData([...packages])
},[packages])