ReactJS передает реквизиты ребенку через Ajax

-2

У меня есть компонент reactjs with redux, который передает асинхронно реквизит для дочернего компонента.

В дочернем компоненте я пытаюсь поймать данные в componentDidMount, но так или иначе не работает, однако дочерний компонент получает визуализацию.

Это мой родительский компонент

import React from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import * as slidesActions from '../../actions/slidesActions';
import Slider from '../Partials/Slider'
import _ from 'underscore';


class HomePage extends React.Component {

    constructor(props) {
        super(props);
    }

    componentDidMount() {
        this.props.actions.getSlides()
    }

    componentWillMount() {
        const {slides} = this.props;
    }

    render() {
        const {slides} = this.props;

        return (
            <div className="homePage">
                <Slider columns={1}  slides={slides} />
            </div>
        );
    }
}

function mapStateToProps(state) {
    return {
        slides: state.slides
    };
}

function mapDispatchToProps(dispatch) {
    return {
        actions: bindActionCreators(slidesActions, dispatch)
    };
}


export default connect(mapStateToProps, mapDispatchToProps)(HomePage);

здесь приходит мой дочерний компонент, где я пытаюсь получить пропущенные слайды, но пуст

import React from 'react';
import _ from 'underscore';
import Hammer from 'hammerjs';


class Slider extends React.Component {

    constructor(props) {
        super(props)
        this.updatePosition = this.updatePosition.bind(this);
        this.next = this.next.bind(this);
        this.prev = this.prev.bind(this);

        this.state = {
            images: [],
            slidesLength: null,
            currentPosition: 0,
            slideTransform: 0,
            interval: null
        };
    }

    next() {
        const currentPosition = this.updatePosition(this.state.currentPosition - 10);
        this.setState({ currentPosition });

    }

    prev() {
        //TODO: work on logic
        if( this.state.currentPosition !== 0) {
            const currentPosition = this.updatePosition(this.state.currentPosition + 10);
            this.setState({currentPosition});
        }
    }


    componentDidMount() {
        //here I try set a state variable on slides 
        let {slides} = this.props
        let slidesLength = slides.length 
        this.setState({slidesLength})

        this.hammer = Hammer(this._slider)
        this.hammer.on('swipeleft', this.next);
        this.hammer.on('swiperight', this.prev);
    }

    componentWillUnmount() {
        this.hammer.off('swipeleft', this.next)
        this.hammer.off('swiperight', this.prev)
    }

    updatePosition(nextPosition) {
        const { visibleItems, currentPosition } = this.state;
        return nextPosition;
    }

    render() {
        let {slides, columns} = this.props
        let {currentPosition} = this.state
        let sliderNavigation = null

        //TODO: this should go to slides actions
        let slider = _.map(slides, function (slide) {
            let Background = slide.featured_image_url.full;
            if(slide.status === 'publish')
                return <div className="slide" id={slide.id}  key={slide.id}><div className="Img" style={{ backgroundImage: 'url(${Background})' }} data-src={slide.featured_image_url.full}></div></div>
        });

        if(slides.length > 1 ) {

          sliderNavigation =   <ul className="slider__navigation">
                <li data-slide="prev" className="" onClick={this.prev}>previous</li>
                <li data-slide="next" className="" onClick={this.next}>next</li>
            </ul>
        }

        return <div ref={
            (el) => this._slider = el
        } className="slider-attached"
                    data-navigation="true"
                    data-columns={columns}
                    data-dimensions="auto"
                    data-slides={slides.length}>
                    <div className="slides" style={{ transform: 'translate(${currentPosition}%, 0px)', left : 0 }}> {slider} </div>

                    {sliderNavigation}
            </div>
    }
}

export default Slider;

и здесь у меня есть свои действия для слайдера

import * as types from './actionTypes';
import axios from 'axios';
import _ from 'underscore';


//TODO: this should be accessed from DataService
if (process.env.NODE_ENV === 'development') {
    var slidesEndPoint = 'http://dev.server/wp-json/wp/v2/slides';
} else {
    var slidesEndPoint = 'http://prod.server/wp-json/wp/v2/slides';
}

export function getSlides () {
    return dispatch => {
        dispatch(setLoadingState()); // Show a loading spinner

        axios.get(slidesEndPoint)
            .then(function (response) {
                dispatch(setSlides(response.data))
                dispatch(doneFetchingData(response.data))
            })
            /*.error((response) => {
                dispatch(showError(response.data))
            })*/

    }
}


function setSlides(data) {
    return {
        type: types.SLIDES_SUCCESS,
        slides: data
    }
}


function setLoadingState() {
    return {
        type: types.SHOW_SPINNER,
        loaded: false
    }
}

function doneFetchingData(data) {
    return {
        type: types.HIDE_SPINNER,
        loaded: true,
        slides: data
    }
}

function showError() {
    return {
        type: types.SHOW_ERROR,
        loaded: false,
        error: 'error'
    }
}
Теги:
react-redux

2 ответа

1
Лучший ответ

Причина в том, что componentDidMount будет вызван только один раз, сразу после первоначального рендеринга, поскольку вы извлекаете данные асинхронно, поэтому перед тем, как вы получите данные, компонент Slider получит визуализацию.

Поэтому вам нужно использовать метод жизненного цикла componentwillreceiveprops.

componentDidMount:

componentDidMount() вызывается сразу после установки компонента. Инициализация, требующая узлов DOM, должна идти здесь. Если вам нужно загружать данные с удаленной конечной точки, это хорошее место для создания экземпляра сетевого запроса. Состояние настройки в этом методе вызовет повторный рендеринг.

componentWillReceiveProps :

componentWillReceiveProps() вызывается до того, как смонтированный компонент получит новые реквизиты. Если вам нужно обновить состояние в ответ на изменения prop (например, для его сброса), вы можете сравнить this.props и nextProps и выполнить переходы состояний, используя this.setState() в этом методе.

Напишите так:

componentWillReceiveProps(nextProps){
     if(nextProps.slides){
         let {slides} = nextProps.props
         let slidesLength = slides.length;        

         this.hammer = Hammer(this._slider)
         this.hammer.on('swipeleft', this.next);
         this.hammer.on('swiperight', this.prev);
         this.setState({slidesLength})
     }
}
0

Насколько я понимаю, вы делаете вызов axios для извлечения данных, а затем устанавливаете его в редукторе, который вы возвращаете позже. Также исходные данные редуктора пустые. Теперь, поскольку componentDidMount вызывается только один раз, и изначально никакие данные не были там, вы не видите никаких значений. Используйте функцию componentWillReceiveProps

componentWillReceiveProps(nextProps) {
        //here I try set a state variable on slides 
        let {slides} = nextProps
        let slidesLength = slides.length 
        this.setState({slidesLength})

        this.hammer = Hammer(this._slider)
        this.hammer.on('swipeleft', this.next);
        this.hammer.on('swiperight', this.prev);
    }

Ещё вопросы

Сообщество Overcoder
Наверх
Меню