создать отдельный компонент реакции для управления файлами cookie - PullRequest
0 голосов
/ 03 мая 2018

У меня есть компонент, который рендерится, если его prop.paramA отличается от значения paramA, хранящегося в cookie.

Ниже приведена моя попытка переместить логику управления файлами cookie в отдельный компонент. Проблема в том, что компонент вопроса отображается только один раз, когда showQuestion имеет значение false, поэтому я никогда не вижу вопрос.

В настоящее время мой код выглядит следующим образом

// question.js
import React from 'react';
import ToggleDisplay from 'react-toggle-display';
import {withCookies, Cookies} from 'react-cookie';

class Question extends React.Component {

    static get propTypes() {
        return {
            cookies: instanceOf(Cookies).isRequired
        }
    }

    constructor(props) {
        super(props);
        this.state = {
            paramA: props.paramA,
            showQuestion: props.showQuestion
        };
    }

    componentDidMount() {
        if (this.state.showQuestion) {
            // do some ajax calls etc.
        }
    }

    render() {
        return (
            <div id="simplequestion">
                <ToggleDisplay show={this.state.showQuestion}>
                    <div>What is your SO profile?</div>
                </ToggleDisplay>
            </div>
        );
    }
}

export default withCookies(Question);

Я написал следующий компонент CookieManager -

// cookiemanager.js
import React from 'react';
import {withCookies, Cookies} from 'react-cookie';

class CookieManager extends React.Component {
    static get propTypes() {
        return {
            cookies: instanceOf(Cookies).isRequired
        }
    }

    constructor(props) {
        super(props);
        let propA = props.cookies.get('propA');
        if (!propA || propA !== props.propA) {
            props.cookies.set('propA', props.propA, { path: '/', maxAge: 604800});
            console.log('changed', propA, props.propA);
            props.propAChanged(true);
        } else if (propA === props.propA) {
            console.log('unchanged', propA, props.propA);
            props.propAChanged(false);
        }
    }
    render() { 
        return <div id="cookieManager"></div>;
    }
}
export default withCookies(CookieManager);

Следующее приложение верхнего уровня

// app.js
import React from 'react';
import Question from './question';
import CookieManager from './cookiemanager';
import { CookiesProvider } from 'react-cookie';


class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            paramA: props.paramA,
            showQuestion: false,
            avoidUpdate: false
        };
        this.updateShowQuestion = this.updateShowQuestion.bind(this);
    }

    updateShowQuestion(x) {
        if (this.state.avoidUpdate) {
            return;
        }
        this.setState({
            paramA: this.state.paramA,
            showQuestion: x,
            avoidUpdate: !this.state.avoidUpdate
        });
    }

    componentWillUpdate(nextProps, nextState) {
        if (!nextState.avoidUpdate && nextState.paramA === this.state.paramA) {
            this.setState({
                paramA: this.state.paramA,
                showQuestion: this.state.showQuestion,
                avoidUpdate: true
            });
        }
    }

    render() {
        return (
            <CookiesProvider>
                <CookieManager paramA={this.state.paramA} ridChanged={this.updateShowQuestion}>
                <Question
                    paramA={this.state.paramA}
                    showQuestion={this.state.showQuestion}/>
                </CookieManager>
            </CookiesProvider>
        );
    }
}
export default App;

1 Ответ

0 голосов
/ 03 мая 2018

Вы читаете из состояния здесь:

<ToggleDisplay show={this.state.showQuestion}>

Но showQuestion устанавливается только один раз, в конструкторе:

this.state = {
    paramA: props.paramA,
    showQuestion: props.showQuestion
};

Когда this.props изменяет ваш компонент, он отображается, но вы все еще читаете из this.state, который не обновлен, поэтому видимый вывод такой же.

Я вижу два способа решения этой проблемы:

  • Обновление this.state.showQuestion при каждом изменении реквизита:

    static getDerivedStateFromProps(nextProps, prevState) {
        if(nextProps.showQuestion !== prevState.showQuestion)
            return { showQuestion };
    }
    
  • В render(), чтение из this.props.showQuestion:

    <ToggleDisplay show={this.props.showQuestion}>
    

    Этот способ может выглядеть проще, но с другим вы получаете более детальный контроль над изменениями состояния.


Другая вещь, которую вы пропустили, находится здесь:

componentWillUpdate(nextProps, nextState) {
    if (!nextState.avoidUpdate && nextState.paramA === this.state.paramA) {
        this.setState({
            paramA: this.state.paramA,
            showQuestion: this.state.showQuestion, // this line
            avoidUpdate: true
        });
    }
}

Вы получаете новые реквизиты, но вы устанавливаете старое состояние: showQuestion: this.state.showQuestion. Вместо этого установите новое значение showQuestion из нового реквизита - nextProps, таким образом:

componentWillUpdate(nextProps, nextState) {
    if (!nextState.avoidUpdate && nextState.paramA === this.state.paramA) {
        this.setState({
            paramA: this.state.paramA,
            showQuestion: nextProps.showQuestion, // this line
            avoidUpdate: true
        });
    }
}
...