Дочерний компонент внутри модального типа неожиданно сбрасывается в состояние по умолчанию, React Native - PullRequest
0 голосов
/ 08 июня 2019

У меня есть родительский компонент - LeagueSelect - и дочерний компонент TeamSelect.

LeagueSelect - это модал React Native.

Когда я открываю LeagueSelect, выполняю корректировку в модале LeagueSelect, сворачиваю модал и снова открываю, изменения состояния сохраняются.

Если я открою LeagueSelect, внесу изменения в TeamSelect в модале LeagueSelect, сверну модал и снова открою, изменения состояния не сохранятся.

Для обеспечения контекста, когда модал (LeagueSelect) открыт, он выглядит следующим образом; первое красное поле является частью LeagueSelect, а второе красное поле является частью TeamSelect: enter image description here

Это мой компонент LeagueSelect; Я думаю, что проблема происходит в setModalVisible, потому что журналы консоли читают правильное состояние, когда я console.log состояние в componentWillUnmount:

class LeagueSelect extends Component {
    constructor(props) {
        super(props)
        this.state = {
            modalVisible: false,
            checked: [],
            checkedLeagues: [],
            uncheckedLeagues: [],
            checkMessage: '',
            firstString: []
        }
    }

    setModalVisible(visible) {
        this.setState({modalVisible: visible})
        if(this.state.checked.length === 0) {
            this.props.league.map(
                (v, i) => {
                    this.state.checked.push(true)
                    this.state.checkedLeagues.push(v.acronym)
                }
            )
        }
        this.setState({ checkMessage: '' })

        matchedTeams = []

        if(undefined !== this.props.teamObject) {
            this.props.teamObject.map(
                (v, i) => {
                    if(this.state.checkedLeagues.includes(v.league.acronym)){
                        matchedTeams.push(v.team_name)
                    }
                }
            )
        }

        queryString = []
            //encodes the teams that have their leagues selected
        matchedTeams.map(
            (v, i) => {
                if (queryString.length < 1) {
                    queryString.push(`?team=${v}`)
                } else if (queryString.length >= 1 ) {
                    queryString.push(`&team=${v}`)
                }
            }
        )

        queryString = queryString !== undefined ? queryString.join('') : ''

        axios.get(`http://localhost:4000/reports${queryString}`)
                .then(response => {
                    this.props.loadCards(response.data)
                })
    }

    componentDidMount() {
        this.props.loadLeagues()
        this.props.loadTeams() 
    }

    componentDidUpdate(){
        console.log(this.props.checkedLeagues)
        console.log('in league - in update - checked Teams', this.props.checkedTeams)
        this.props.changeLeagues(this.props.league, this.state.checkedLeagues, this.props.checkedTeams, this.props.queryTeams, this.props.teamObject)
    }

    render(){
      return (

        <View style={{ position: 'relative'}}>
              <Modal
                animationType="slide"
                transparent={false}
                visible={this.state.modalVisible}
                onRequestClose={() => {
                Alert.alert('Modal has been closed.');
                }}
              >

                <View
                    style={{
                        marginTop: 100
                    }}
                >

                    <TouchableHighlight
                        onPress={() => {
                            this.setModalVisible(!this.state.modalVisible);
                        }}
                    >
                        <Image
                            source={require('../assets/exit.png')}
                            style={{
                                height: 20,
                                width: 20,
                                left: 320,
                                resizeMode: 'contain'
                            }}
                        />
                    </TouchableHighlight>
                        <Text
                            style={{
                                paddingTop: 8,
                                paddingLeft: 5,
                                fontSize: 15,
                                fontFamily: 'Helvetica',
                                fontSize: 13
                            }}
                        >LEAGUE SELECT</Text>
                        <View
                            style={{
                                flexDirection:"row",
                                paddingLeft: 10
                            }}
                        >
                            {this.props.league === null ?'' : this.props.league.map(
                                (v, i) => {
                                    return(
                                            <View 
                                                key={i}
                                                style={{
                                                    alignSelf: 'flex-end',
                                                    flexDirection:"row",
                                                    top: 4,
                                                    paddingRight: 10
                                                }}
                                            >
                                                <Check
                                                    checked={this.state.checked[i]}
                                                    index={i}
                                                    value={v.acronym}
                                                    changeCheck={this.changeCheck}
                                                    style={{
                                                        paddingRight: 10
                                                    }}
                                                />
                                            </View>
                                    )
                                }
                            )}
                        </View>
                    <Text
                        style={{
                            paddingLeft: 10,
                            paddingTop: 12,
                            fontStyle: 'italic',
                            color: '#F4AF0D'
                        }}
                    >{this.state.checkMessage}</Text>
                    <TeamSelect />
                </View>
              </Modal>

              <TouchableHighlight
                onPress={() => {
                  this.setModalVisible(true);
                }}>
                <Icon
                    style={{
                        position: 'absolute',
                        top: -34,
                        right: 10,
                        fontSize: 25,
                        color: 'grey' 
                    }}
                    name='settings'
                />
              </TouchableHighlight>

            </View>
      );
    }
  }

function mapStateToProps(state) {
    return {
      league: state.league.league,
      team: state.team.team,
      checkedLeagues: state.league.checkedLeagues,
      checkedTeams: state.league.checkedTeams,
      queryTeams: state.league.queryTeams,
      teamObject: state.league.teamObject
     }
   }

export default connect(mapStateToProps, { loadCards, loadLeagues, loadTeams, changeLeagues })(LeagueSelect)

Это компонент TeamSelect, в котором выполняется выбор второго красного поля:

class TeamSelect extends Component {
    constructor(props) {
        super(props)
        this.state = {
            checked: [],
            checkedTeams: [],
            teamObject: [],
            queryString: [],
            accordionStatus: [true, true, true]
        }
    }

    componentDidMount(){
        console.log('did mount - checked Teams State', this.state.checkedTeams)
        //updates checked teams on load
        if(this.state.count === false && this.state.checkedTeams.length === 0 && this.state.checked.length === 0){
            this.setState({ count: true})
            this.props.team.map(
                (v, i) => {
                    if(this.props.checkedLeagues.includes(v.league.acronym)) {
                        this.state.checked.push(true)
                        this.state.checkedTeams.push(v.team_name)
                        this.state.teamObject.push(v)
                    } else if (this.state.checkedTeams !== undefined) {
                        this.state.checked.push(false)
                    }
                }
            )
            this.forceUpdate()
        }
    }

    componentWillUnmount(){console.log("unmount - count", this.state.count)
        console.log('will unmount - checked Teams State', this.state.checkedTeams)
    }

    componentDidUpdate(){
        this.props.changeLeagues(this.props.league, this.props.checkedLeagues, this.state.checkedTeams, this.state.queryString, this.state.teamObject)
    }

    changeCheck = (index, name, teamObject) => {
        //updates checked team state
        //prevents all teams being unselected
        if(name === this.state.checkedTeams[0]) {
            this.setState({ checkMessage: `Don't you want something to look at?` })
        } else {
            if(!this.state.checkedTeams.includes(name)){
                this.state.checkedTeams[this.state.checkedTeams.length] = name
                this.setState({ checkedTeams: [...this.state.checkedTeams] })
                //sets team object with new team object
                this.state.teamObject[this.state.teamObject.length] = teamObject
                this.setState({ teamObject: this.state.teamObject })
            } else {
                newChecked  = this.state.checkedTeams.filter(v => { return v !== name})
                this.setState({ checkedTeams: newChecked })
                //removes team object and sets new state
                newObjectChecked = this.state.teamObject.filter(v => { return v.team_name !== teamObject.team_name})
                this.setState({ teamObject: newObjectChecked })

            }

            //updates checkbox for specific space
            this.state.checked[index] = !this.state.checked[index]
            this.setState({ checked: this.state.checked })
        }
    }

    changeTeamSelect = (index) => {
        this.state.accordionStatus[index] = !this.state.accordionStatus[index]
        this.setState({ accordionStatus: this.state.accordionStatus})
    }

    render(){
        return(
            <View>
                <View>
                    <Text
                        style={{
                            fontFamily: 'Helvetica',
                            fontSize: 13,
                            paddingLeft: 5,
                            paddingBottom: 5
                        }}
                        onPress={()=> this.changeTeamSelect(0)}
                    >
                        NFL TEAM SELECT
                    </Text>
                </View>
                {
                    this.state.accordionStatus[0] === false ? null :
                        <View
                        style={{
                            flexDirection: 'row',
                            paddingLeft: 10,
                            flexWrap: 'wrap'
                        }}
                    >
                        { 
                            this.props.team.map(
                                (v, i) => {
                                    if(v.league.acronym === 'NFL'){
                                        return(
                                            <Check
                                                key={i}
                                                checked={ /*this.props.checkedLeagues.includes(v.league.acronym) ?*/ this.state.checked[i] /*: false*/ }
                                                index={i}
                                                teamObject={v}
                                                value={v.team_name}
                                                changeCheck={this.changeCheck}
                                            />
                                        )
                                    }

                                }
                            )

                        }
                    </View>
                }
                <View>
                    <Text
                        style={{
                            fontFamily: 'Helvetica',
                            fontSize: 13,
                            paddingLeft: 5,
                            paddingBottom: 5
                        }}
                        onPress={()=> this.changeTeamSelect(1)}
                    >
                        NBA TEAM SELECT
                    </Text>
                </View>
                {
                    this.state.accordionStatus[1] === false ? null :
                    <View
                        style={{
                            flexDirection: 'row',
                            paddingLeft: 10,
                            flexWrap: 'wrap'
                        }}
                    >
                        { 
                            this.props.team.map(
                                (v, i) => {
                                    if(v.league.acronym === 'NBA'){
                                        return(
                                            <Check
                                                key={i}
                                                checked={ /*this.props.checkedLeagues.includes(v.league.acronym) ?*/ this.state.checked[i] /*: false*/ }
                                                index={i}
                                                teamObject={v}
                                                value={v.team_name}
                                                changeCheck={this.changeCheck}
                                            />
                                        )
                                    }

                                }
                            )

                        }
                    </View>
                }
                <View>
                    <Text
                        style={{
                            fontFamily: 'Helvetica',
                            fontSize: 13,
                            paddingLeft: 5,
                            paddingBottom: 5
                        }}
                        onPress={()=> this.changeTeamSelect(2)}
                    >
                        MLB TEAM SELECT
                    </Text>
                </View>
                {
                    this.state.accordionStatus[2] === false ? null :
                    <View
                        style={{
                            flexDirection: 'row',
                            paddingLeft: 10,
                            flexWrap: 'wrap'
                        }}
                    >
                        { 
                            this.props.team.map(
                                (v, i) => {
                                    if(v.league.acronym === 'MLB'){
                                        return(
                                            <Check
                                                key={i}
                                                checked={ /*this.props.checkedLeagues.includes(v.league.acronym) ?*/ this.state.checked[i] /*: false */}
                                                index={i}
                                                teamObject={v}
                                                value={v.team_name}
                                                changeCheck={this.changeCheck}
                                            />
                                        )
                                    }

                                }
                            )

                        }
                    </View>
                }
            </View>
        )
    }
}

function mapStateToProps(state) {
    return {
      league: state.league.league,
      team: state.team.team,
      checkedLeagues: state.league.checkedLeagues,
      checkedTeams: state.league.checkedTeams,
      queryTeams: state.league.queryTeams
    }
}

export default connect(mapStateToProps, { loadCards, changeLeagues })(TeamSelect)

Что-то, на что стоит обратить внимание, я использую Redux для обновления состояния, помещаю его в хранилище, а затем использую его, когда компонент снова монтируется. Интересно то, что this.state.checkedLeagues сохраняет состояние, как и должно быть в первом компоненте, однако this.state.checkedTeams не сохраняет свое состояние во втором компоненте. Есть идеи почему?

EDIT:

Это мой LeagueReducer:

let defaultState = {
    league: null,
    checkedLeagues: null,
    checkedTeams: null,
    queryTeams: null,
    teamObject: null
}

export function LeagueReducer(state = defaultState, action){
    if(action.type === "CHANGE_LEAGUES") {
        return {
            ...state,
            league: action.league,
            checkedLeagues: action.checkedLeagues,
            checkedTeams: action.checkedTeams,
            queryTeams: action.queryTeams,
            teamObject: action.teamObject
        }
    } else {
       return state
    }
}

1 Ответ

0 голосов
/ 08 июня 2019

Похоже, что вы не обновляете хранилище должным образом.Помните, что не используйте функции массива, которые изменяют массив как push.Вам нужно использовать такие функции, как concat, которые возвращают новый массив.

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