Skip to content
Advertisement

React-Redux: Data not read during initial render in useState

I am trying to get a list of data called packages and put it in a table. Added filter and sorting to it.

  • I get packages from pakageList reducer
  • Assign to data state
  • Then add soring and filtering logic and assign data to variable called filteredPackages Everything seems fine but when the page initially loads the contents of the table is empty i.e, the data state is empty. This happens while adding or deleting a package and render occurs as well. Once I go back and come to this screen again the data loads. The data is present in the packages which I get from reducers but it does not get assigned to the data state. Can anyone try checking and let me know what can be done here. Sorry if my code is not good. Thanks in advance.

Skipping code which is not necessary

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 and filteredPackage both are empty at initial renders. I tried the below in useEffect but no luck

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] )

Please let me know if you need further details.

Advertisement

Answer

Make a const for packages and assign this to your data state

const packages = useSelector(state => state.packageList.packages)
...
const [ data, setData ] = useState(packages) 

and write a useEffect that updates your data state when ever your package store value renders

useEffect(()=>{
   setData([...packages])
},[packages])
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement