模式内部的子组件意外重置为默认状态,React Native

时间:2019-06-08 02:44:20

标签: javascript reactjs react-native redux

我有一个父组件(LeagueSelect)和一个子组件TeamSelect。

LeagueSelect是一个React Native模式。

当我打开LeagueSelect时,在LeagueSelect模式中进行调整,折叠模式,然后再次打开,状态更改将保留。

如果我打开LeagueSelect,在LeagueSelect模式中对TeamSelect进行调整,折叠模式,然后再次打开它,状态更改将不会保留。

为了提供上下文,当模式(LeagueSelect)打开时,它是这样的;第一个红色框是LeagueSelect的一部分,第二个红色框是TeamSelect的一部分: enter image description here

这是我的LeagueSelect组件;我认为问题是在setModalVisible中发生的,因为当我进行console时,控制台日志会读取正确的状态。在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不能在第二个组件中保留其状态。有什么想法吗?

编辑:

这是我的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 :(得分:0)

看起来您可能未正确更新Redux存储。切记不要使用像push这样使数组变异的数组函数。您需要使用concat之类的函数来返回新数组。