Объединение глобального избыточного хранилища с локальным состоянием компонента - PullRequest
0 голосов
/ 23 апреля 2020

Проблема, с которой я столкнулся, заключается в использовании глобального хранилища, а именно «жанров», представляющих собой массив объектов, в локальном состоянии для манипуляции установкой / снятием флажков. Проблема возникает, когда я пытаюсь использовать props.genres в исходном состоянии. Похоже, я получаю пустой массив из props.genres при инициализации локального состояния.

const Filters = (props) => {
    const { genres, getSelected, loadGenres, getGenres, clearFilters } = props
    const [isChecked, setIsChecked] = useState(() =>
        genres.map(genre => (
            {id: genre.id, value: genre.name, checked: false}
        ))
    )
    const optionsSortBy = [
        {name: 'Popularity descending', value: 'popularity.desc'},
        {name: 'Popularity ascending', value: 'popularity.asc'},
        {name: 'Rating descending', value: 'vote_average.desc'},
        {name: 'Rating ascending', value: 'vote_average.asc'},
    ]
    const d = new Date()
    let currentYear = d.getFullYear()
    let optionsReleaseDate = R.range(1990, currentYear + 1).map(year => (
        {name: year + '', value: year}
    ))

    useEffect(() => {
        const url = `${C.API_ENDPOINT}genre/movie/list`
        loadGenres(url, C.OPTIONS)
    }, [])

    const handleCheckbox = (e) => {
        let target = e.target
        getGenres(target)
    }

    const handleSelect = (e) => {
        let target = e.target
        let action = isNaN(target.value) ? 'SORT_BY' : 'RELEASE_DATE'
        getSelected(action, target)
    }

    const handleSubmitBtn = (e) => {
        e.preventDefault()
        clearFilters()
    }

    return (
        <form className={classes.FiltersBox}>
            <Submit submited={handleSubmitBtn} />
            <Select name="Sort By:" options={optionsSortBy} changed={handleSelect} />
            <Select name="Release date:" options={optionsReleaseDate} changed={handleSelect} />
            <Genres genres={isChecked} changed={handleCheckbox} />
        </form>
    )
}

const mapStateToProps = (state) => {
    return {
        genres: state.fetch.genres,
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        loadGenres: (url, options) => dispatch(A.getApiData(url, options)),
        getGenres: (targetItem) => dispatch({
            type: 'CHECK_GENRES',
            payload: targetItem
        }),
        getSelected: (actionType, targetItem) => dispatch({
            type: actionType,
            payload: targetItem,
        }),
        clearFilters: () => dispatch({type: 'CLEAR_FILTERS'})
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(Filters);
import * as R from 'ramda';
import fetchJSON from '../utils/api.js';

export const getApiData = (url, options) => async (dispatch) => {
    const response = await fetchJSON(url, options)
    const data = response.body
    const dataHas = R.has(R.__, data)
    let actionType = dataHas('genres') ? 'FETCH_GENRES' : 'FETCH_MOVIES'

    dispatch({
        type: actionType,
        payload: data
    })
}
export const fetchReducer = (state = initialState, action) => {
    const { payload } = action
    if (action.type === 'FETCH_GENRES') {
        return {
            ...state,
            isLoading: false,
            genres: [...payload.genres]
        }
    }
    if (action.type === 'FETCH_MOVIES') {
        return {
            ...state,
            isLoading: false,
            movies: [...payload.results]
        }
    }
    return state
}

Ответы [ 2 ]

0 голосов
/ 23 апреля 2020

Вы подходите почти правильно. Я не уверен, как должно выглядеть состояние, когда вы получили свои данные. Я могу видеть в mapStateToProps пытается получить доступ к значению, которое не определено в начале. Если state.fetch равно undefined, то вы не можете получить доступ к genres.

Попытка 1: вы можете решить эту проблему с помощью loda sh .get https://lodash.com/docs/#get Она наверстает упущенное для проблемы undefined.

Попытка 2: Вы можете определить начальное состояние, в котором ваши значения определяются с помощью фиктивных данных.

const initialState = {fetch: {genres: []}}

и используйте его в своем редукторе

0 голосов
/ 23 апреля 2020

То, что вы пытаетесь сделать, устанавливая начальное значение для состояния из реквизита, возможно, но не реагирует на лучшие практики. Рассмотрите начальные данные как пустой массив и через useEffect манипулируйте состоянием


 // didn't understand if its array or bool
 const [isChecked, setIsChecked] = useState([])
 useEffect(()=>genres&& {  setIsChecked(... perform action...)
                                 }   ,[genres])
...