Проблемы с отображением изменений состояния redux в реагирующих компонентах - PullRequest
0 голосов
/ 26 мая 2020

Обновление исходного сообщения: Я понял, что проблема в том, что обновления в состоянии Redux (свойства компонента WaitingRoom) каким-то образом устанавливают все состояние компонента в его исходное состояние. Таким образом, для параметра showmatchingwindow также было установлено значение false. Первоначально после отправки MATCHING_REQUEST и установки для параметра "loading" значения true состояние компонента WaitingRoom по-прежнему оставалось неизменным. Однако после того, как MATCHING_SUCCESS был отправлен и «загрузка» стала ложной, а «buddy» и «chatid» в состоянии Redux были обновлены, все поля в состоянии WaitingRoom каким-то образом были сброшены до своих начальных значений. Это странно и не происходило с другими моими действиями Redux. Мне интересно, может ли кто-нибудь помочь мне объяснить, чем это вызвано. Благодарим вас за терпение и любую помощь, которую вы можете предложить!

Ссылка на репозиторий Github : https://github.com/liu550/salon_project (Компонент WaitingRoom находится в src / components / waitroom. js

/// Ниже оригинальное сообщение ///

Я создаю функцию случайного сопоставления для своего веб-сайта. Вот краткое описание : Я хочу, чтобы окно чата всплывало после успешного сопоставления двух пользователей. В моем состоянии Redux у меня есть (1) «загрузка», (2) «приятель», представляющий идентификатор пользователя, которого наш текущий пользователь сопоставляется с (3) "chatid", представляющим идентификатор документа firestore, в котором хранится история чата между двумя пользователями. Действие startMatching Redux вызывается в компоненте WaitingRoom, который представляет собой веб-страницу, которая дополнительно отображает профили других пользователей Окно чата - это компонент MatchingWindow, которому требуется chatid в качестве реквизита для отображения соответствующей истории чата между двумя пользователями.

Я уверен, что t что мои действия Redux работают нормально, но возникли проблемы при передаче обновленного состояния Redux в мои компоненты React. Ниже приведены 2 подхода, которые я пробовал:

Подход 1 : отображение окна чата внутри модального окна, возвращаемого компонентом WaitingRoom. Как видите, то, что я здесь делаю, - это просто условный рендеринг. Однако при таком подходе модальное окно каким-то образом быстро появилось менее чем на секунду, а затем исчезло вместе с предыдущим модальным окном, в котором пользователи выбирают свои гендерные предпочтения. Проверяя свойства компонента WaitingRoom, я обнаружил, что «buddy» и «chatid» действительно были обновлены. Не следует ли отображать MatchingWindow? Я также попытался просто поставить success> вместо компонента MatchingWindow, и результат был тот же.

Подход 1 (Комната ожидания)

class WaitingRoom extends Component {

    state = {
      ......
    }

    showMatching = (e) => {
      e.preventDefault();
      this.setState({
        showmatching: true
      })
    }

    handleMatching = (e) => {
      e.preventDefault();
      this.props.startMatching(this.props.auth.uid, this.props.profile, this.props.profile.gender, this.state.genderpreference);
      this.setState({
        showmatchingwindow: true
      })
    }

    closeMatching = () => {
      this.setState({
        showmatching: false
      })
    }


      render() {

        const { auth, users, profile, loading, sent, buddy, chatid } = this.props;


        return (

            <div>
            <Button variant="success" onClick={this.showMatching} style={{ fontSize: "large", fontFamily: "Comic Sans MS, cursive, sans-serif"}}>Randomly find a study/work buddy instantly!</Button>
            </div>


            <Modal show={this.state.showmatching} onHide={this.closeMatching}>
              <Modal.Header closeButton></Modal.Header>
              <Modal.Body>
                <form onSubmit={this.handleMatching}>
                  Match me with:
                  <div className="form-inline">
                        <div className="radio-container">
                            <label>Male only</label><input type="radio" id="genderpreference" value="Male" onChange={this.handleChange} checked={this.state.genderpreference === "Male"} />   
                        </div>

                  ......

                  </div>

                  <button>Start matching</button>
                </form>
              </Modal.Body>
            </Modal>

            <Modal show={this.state.showmatchingwindow} onHide={this.closeMatching}>
              <Modal.Header closeButton></Modal.Header>
              <Modal.Body>
                { loading ?  <div class="loader"></div> : null}
                { buddy !== "" && loading === false ? <MatchingWindow chatid=chatid /> : null }
                { buddy === "" && loading === false ? <span>Sorry we cannot help you find a study/work buddy currently</span> : null }
              </Modal.Body>
            </Modal>

        );
      }
    }

const mapStateToProps = (state) => {
  return {
    users: state.firestore.ordered.users,
    auth: state.firebase.auth,
    profile: state.firebase.profile,
    loading: state.auth.loading,
    sent: state.auth.sent,
    buddy: state.auth.buddy,
    chatid: state.auth.chatid
  }
}

export default compose(
connect(mapStateToProps, {submitTicket, startMatching, groupMessaging}),
firestoreConnect([
{ collection: 'users' }
])
)(WaitingRoom);

Подход 2 : Создайте отдельный компонент MatchingBox, который будет отображать разные элементы / компоненты на основе разных состояний. Однако, когда я использовал этот подход, componentWillReceiveProps () не запускался после изменения состояния Redux, так как console.log (), который я поместил внутри метода, не выполнялся. Это было странно, потому что, как я упоминал в подходе 1, состояние Redux действительно было изменено, когда я проверил реквизиты для компонента WaitingRoom, что означает, что мой код действия и редуктора Redux должен быть в порядке, и он должен работать так же для компонента MatchingBox. также. В результате того, что componentWillReceiveProps () не был запущен, chatid, который я передал компоненту MatchingWindow, был пустой строкой, что является проблемой c. Я попробовал componentDidUpdate (), и он тоже не сработал.

Подход 2 (Комната ожидания)

class WaitingRoom extends Component {

      render() {

        return (

            ......All the same except for replacing the second Modal with:
            { this.state.showmatchingwindow ? <MatchingBox /> : null }

        );
      }
    }

Подход 2 (MatchingBox)

class MatchingBox extends Component {

    state = {
        loading: true,
        chatid: "",
        buddy: []
    }

    componentDidMount() {
        console.log(this.props.loading);
        console.log(this.props.chatid);
        console.log(this.props.buddy);
        this.setState({
            loading: this.props.loading,
            chatid: this.props.chatid,
            buddy: this.props.buddy
        })
    }


    componentWillReceiveProps() {
        console.log(this.props.chatid);
        console.log(this.props.buddy);
        this.setState({
            loading: this.props.loading,
            chatid: this.props.chatid,
            buddy: this.props.buddy
            })
        }

    render() {
        let box;
        if (this.props.loading === true) {
            box = <div class="loader"></div>
        }
        else {
            if (this.props.buddy !== "") {
                box = <div>
                <MatchingWindow chatid={this.state.chatid} />
                </div>    
            }
            else {
                box = <span>Sorry</span>
            }
        }
        return (
            <div>
                {box}
            </div>

        );
    }

}

const mapStateToProps = (state) => {
    return {
        auth: state.firebase.auth,
        loading: state.auth.loading,
        chatid: state.auth.chatid,
        buddy: state.auth.buddy,
        profile: state.firebase.profile
    };
}

export default connect(mapStateToProps)(MatchingBox);

Как указано выше, я почти уверен, что мои действия с редуктором и редуктор в порядке, но просто хочу, чтобы мое описание было более понятным.

Действия Redux

export const startMatching = (userid, userprofile, usergender, genderpreference) => (dispatch) => {

    dispatch({ type: MATCHING_REQUEST });

    ......

    dispatch(matchingConversation(userspool[number].id, doc.data(), userprofile, {time: "", from: "", content: ""}, number, userspool));      
}

export const matchingConversation = (user2id, user2profile, user1profile, message, number, userspool) => (dispatch, getState) => {

      .....
                .then(() => {
                    dispatch({ type: CHAT_SUCCESS, payload: doc.id });
                })
                .then(() => {
                    dispatch({ type: MATCHING_SUCCESS, payload: user2id });
                })
}

Редуктор

const initialState = {
    loading: false,
    chatid: "",
    buddy: "",
}

const authReducer = (state = initialState, action) => {
    const {type, payload} = action;

    switch(type) {
        ......

        case CHAT_SUCCESS:
            return {
                ...state,
                chatid: action.payload
            }
        case MATCHING_REQUEST:
            return {
                ...state,
                loading: true
            }
        case MATCHING_SUCCESS:
            return {
                ...state,
                buddy: action.payload,
                loading: false
            }
        case MATCHING_FAIL:
            return {
                ...state,
                buddy: action.payload,
                loading: false
            }
        default: return state;
    }
}

Ответы [ 2 ]

0 голосов
/ 29 мая 2020

Кажется, вы используете функцию для возврата компонента:

// main.js
const WaitingRoomPage = () => {
  return <WaitingRoom />;
};

...

<Route path='/waitingroom' component={WaitingRoomPage} />

Я не думаю, что вы должны это делать, потому что каждый повторный рендеринг Main заставит WaitingRoom сохранить перемонтирование (и, таким образом, повторная инициализация) . Ваш WaitingRoom не является функциональным компонентом, и даже если бы он был, вы все равно должны просто использовать более простой способ объявления Route с атрибутом component:

<Route path='/waitingroom' component={WaitingRoom} />
0 голосов
/ 26 мая 2020

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

Во-вторых, я думаю, что в вашем редукторе вы можете указывать на одно и то же начальное состояние и напрямую изменяя его (против правил редукции). Короче говоря, из-за неглубокой копии ваше состояние может указывать на тот же старый объект начального состояния, и, следовательно, ваш компонент реакции не обнаруживает изменения.

Попробуйте создать глубокую копию (а не мелкую копию) вашего исходного состояния в редукторе redux, прежде чем возвращать новое состояние. Эти ссылки говорят об этих концепциях:

  1. https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns
  2. Компонент React не обновляется при изменении состояния хранилища

Наконец, не должен ли ваш приятель в начальном состоянии быть пустым массивом вместо строки?

...