Search code examples
reactjstypescriptredux-toolkit

Component render every page reload


I have project with TS+REACT+REDUX TOOLKIT and i fetch some data to my items array. Then using redux toolkit i give to filterMenu (alphabet and birthday filter) and filterSearch (input search) data to filter state in my Main component. And if the filtered array is empty i want to render component SearchFail .

But, when i reload page i got a SearchFail component in a second and then laod my data. I have a slice of users which include isLoading, error and items in state, and initial state of items is empty array, and when i reload page i got my array length 0. So how can i prevent this component loading in this case?

Main.tsx component:

const Main:React.FC = () => {

    const {items, isLoading, error} = useAppSelector(state => state.user)
    const {filterSearch, filterMenu, filter} = useAppSelector(state => state.filter)
    const dispatch = useAppDispatch()

    const filterItems = filterMenu === 'alphabet' ? items.slice().sort((a,b) => a.firstName.localeCompare(b.firstName)).filter(item => {
        if (filterSearch === '') {
            return item
        } else {
            return item.firstName.toLowerCase().includes(filterSearch.toLowerCase()) ||
                item.lastName.toLowerCase().includes(filterSearch.toLowerCase()) ||
                item.userTag.toLowerCase().includes(filterSearch.toLowerCase())
        }
    }) : (
        items.slice().sort((a,b) => a.birthday.localeCompare(b.firstName)).filter(item => {
            if (filterSearch === '') {
                return item
            } else {
                return item.firstName.toLowerCase().includes(filterSearch.toLowerCase()) ||
                    item.lastName.toLowerCase().includes(filterSearch.toLowerCase()) ||
                    item.userTag.toLowerCase().includes(filterSearch.toLowerCase())
            }
        })
    )

    useEffect(() => {
        dispatch(getUsers(filter))
        const timer = setInterval(() => {
            dispatch(getUsers(filter))
        }, 50000)
        return () => clearInterval(timer)
    }, [filter])

    return (
        <main className='main'>
            {error && <ErrorPage/>}
            {isLoading ? <SkeletonItem count={6}/> :
                (filterItems.length === 0) ? <SearchFail/> :
                    <div className="main__wrapper">
                        {
                            filterItems.map(item => (
                                <MainItem data={item} key={item.id}/>
                            ))
                        }
                    </div>
            }
        </main>
    );
};

user-slice.ts:

import {createAsyncThunk, createSlice} from "@reduxjs/toolkit";
import {IItmes, IUser} from "./user-types";
import axios from "axios";


const initialState: IItmes = {
    items: [],
    isLoading: false,
    error: ''
}

export const getUsers = createAsyncThunk<IUser[], string, {rejectValue: string}>(
    'user/getUsers',
    async (filterName, {rejectWithValue}) => {
        try {
            const res = await axios.get(`https://stoplight.io/mocks/kode-frontend-team/koder-stoplight/86566464/users?__example=${filterName}`)
            return res.data.items
        } catch (e) {
            return rejectWithValue('critical-error')
        }
    }
)

export const userSlice = createSlice({
    name: 'user',
    initialState,
    reducers: {},
    extraReducers: builder =>
        builder
            .addCase(getUsers.pending, state => {
                state.isLoading = true
                state.error = ''
            })
            .addCase(getUsers.fulfilled, (state, action) => {
                state.items = action.payload
                state.isLoading = false
                localStorage.setItem('items', JSON.stringify(action.payload))
            })
            .addCase(getUsers.rejected, (state, action) => {
                state.isLoading = false
                if (action.payload) {
                    state.error = action.payload
                }
            })
})

export const userReducer = userSlice.reducer

types for user-slice (user-types.ts):

export interface IItmes {
    items: IUser[],
    isLoading: boolean,
    error: string,
}

export interface IUser {
    id: string,
    avatarUrl: string,
    firstName: string,
    lastName: string,
    userTag: string,
    department: string,
    position: string,
    birthday: string,
    phone: string
}

Thanks for help!


Solution

  • Setting isLoading state to true initially would solve the issue.