Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 避免父组件重置子组件状态_Reactjs_React Native - Fatal编程技术网

Reactjs 避免父组件重置子组件状态

Reactjs 避免父组件重置子组件状态,reactjs,react-native,Reactjs,React Native,我正在我的应用程序中实现日志功能,我有一个主日志组件,它有一个部分列表,可以呈现许多日志组件(也称为一天的条目) 当您按下JournalEntriesComponent时,您可以展开所述条目的文本来阅读全部内容。这由本地状态This.state.isTextExpanded管理 我的问题是,当我在父组件中执行this.setState({})时,我孩子的JournalEntriesComponent状态会被重置,即this.state.istextanded键变为false(即默认值) 在我的父

我正在我的应用程序中实现日志功能,我有一个主
日志组件
,它有一个
部分列表
,可以呈现许多
日志组件
(也称为一天的条目)

当您按下
JournalEntriesComponent
时,您可以展开所述条目的文本来阅读全部内容。这由本地状态
This.state.isTextExpanded
管理

我的问题是,当我在父组件中执行
this.setState({})
时,我孩子的
JournalEntriesComponent
状态会被重置,即
this.state.istextanded
键变为
false
(即默认值)

在我的父组件中,我有一个
onHandleScroll
方法来隐藏一些东西,这导致了我的问题,但我也注意到其他东西也有同样的行为

我的问题是:当我的父组件调用
this.setState({})
时,如何避免重置我的孩子的状态

我的代码:

子组件:

class JournalEntryComponent extends PureComponent {
  constructor(props) {
    super(props)
    if (Platform.OS === 'android') {
      UIManager.setLayoutAnimationEnabledExperimental &&
        UIManager.setLayoutAnimationEnabledExperimental(true)
    }
    this.state = { isTextExpanded: false }
    this.onExpand = this.onExpand.bind(this)
    this.onRegenerateData = this.onRegenerateData.bind(this)
    this.deriveColorGradientFromRating = this.deriveColorGradientFromRating.bind(
      this
    )
  }

  onRegenerateData() {
    return this.props.generateSectionListData()
  }

  onExpand() {
    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
    return this.setState({ isTextExpanded: !this.state.isTextExpanded })
  }

  deriveColorGradientFromRating(rating) {
    // decide wether to show custom moood or a default mood by looking into settings in props
    const {
      colorPalette,
      customMoodSelected,
      shouldUseDefaultColorPalettes,
    } = this.props.settings.moodColorCategory

    const mapRatingToArrayIndex = { [5]: 0, [4]: 1, [3]: 2, [2]: 3, [1]: 4 }

    if (!shouldUseDefaultColorPalettes) {
      // find the correct custom color palette and return array with colors
      let relevantArrayOfGradients = this.props.settings.moodColorCategory[
        customMoodSelected
      ]

      let darkColor =
        relevantArrayOfGradients[mapRatingToArrayIndex[rating]].dark
      let lightColor =
        relevantArrayOfGradients[mapRatingToArrayIndex[rating]].light

      return [lightColor, darkColor]
    }

    // else return color gradients from default color palettes
    return COLOR_MAP[colorPalette].colorMap[rating].colors
  }

  render() {
    const { isTextExpanded } = this.state
    const { element, isExpandedFromParent, onDisplayDayMoodPress } = this.props

    console.log('isTextExpanded', isTextExpanded)

    return (
      <View style={styles.sectionEntryContainer}>
        <View style={styles.sectionDayContainer}>
          <LinearGradient
            style={styles.gradientDayStyle}
            start={{ x: 0, y: 0 }}
            end={{ x: 1, y: 0 }}
            colors={this.deriveColorGradientFromRating(
              element.item.data.rating
            )}
          >
            {Platform.OS === 'ios' ? (
              <View style={styles.blackLayer}>
                <Text style={styles.sectionDayText} numberOfLines={1}>
                  {element.item.day}
                </Text>
              </View>
            ) : (
              <View style={styles.blackLayerAndroid}>
                <Text style={styles.sectionDayTextAndroid} numberOfLines={1}>
                  {element.item.day}
                </Text>
              </View>
            )}
          </LinearGradient>
        </View>
        <View style={styles.sectionDayDescriptionContainer}>
          <TouchableWithoutFeedback onPress={this.onExpand}>
            <LinearGradient
              style={styles.gradientDescriptionStyle}
              start={{ x: 0, y: 1 }}
              end={{ x: 0, y: 0 }}
              colors={['#d4d5d6', '#eef2f3']}
            >
              <Text
                style={styles.sectionDescriptionText}
                numberOfLines={
                  isTextExpanded || isExpandedFromParent ? null : 2
                }
              >
                {element.item.data.optionalDescription}
              </Text>
            </LinearGradient>
          </TouchableWithoutFeedback>

          {isTextExpanded ? (
            <TouchableOpacity
              style={styles.gradientButtonContainer}
              onPress={() =>
                onDisplayDayMoodPress(element.item.day, element.item.month)
              }
            >
              <LinearGradient
                style={styles.gradientButtonStyle}
                start={{ x: 0, y: 1 }}
                end={{ x: 0, y: 0 }}
                colors={['#d4d5d6', '#eef2f3']}
              >
                <Icon name={'ios-arrow-forward'} style={styles.arrowStyle} />
              </LinearGradient>
            </TouchableOpacity>
          ) : null}
        </View>
      </View>
    )
  }
}

const mapStateToProps = state => {
  return {
    settings: state.settings,
  }
}

export default JournalEntryComponent
class JournalComponent extends PureComponent {
  constructor(props) {
    super(props)
    if (Platform.OS === 'android') {
      UIManager.setLayoutAnimationEnabledExperimental &&
        UIManager.setLayoutAnimationEnabledExperimental(true)
    }

    this.state = {
      sectionListData: [],
      expandAllEntries: false,
      emotionSurveyDateToDisplay: null,
      isShowEmotionSurveyVisible: false,
      isCloseJournalModeButtonVisible: true,
    }

    this.onHandleScroll = this.onHandleScroll.bind(this)
    this.renderMonthHeader = this.renderMonthHeader.bind(this)
    this.renderMonthEntries = this.renderMonthEntries.bind(this)
    this.onExpandAllEntries = this.onExpandAllEntries.bind(this)
    this.onCloseJournalMode = this.onCloseJournalMode.bind(this)
    this.onDisplayDayMoodPress = this.onDisplayDayMoodPress.bind(this)
    this.generateSectionListData = this.generateSectionListData.bind(this)
  }

  componentWillMount() {
    return this.generateSectionListData()
  }

  componentWillReceiveProps(nextProps) {
    if (
      this.props.moods[moment().format('YYYY')] !==
      nextProps[moment().format('YYYY')]
    ) {
      return this.generateSectionListData(
        nextProps.moods[moment().format('YYYY')]
      )
    }
  }

  onHandleScroll(scrollEvent) {
    console.log(scrollEvent.nativeEvent.contentOffset.y)
    if (scrollEvent.nativeEvent.contentOffset.y > height * 2) {
      if (this.state.isCloseJournalModeButtonVisible) {
        LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
        return this.setState({ isCloseJournalModeButtonVisible: false })
      }
    } else if (scrollEvent.nativeEvent.contentOffset.y < height * 2) {
      if (!this.state.isCloseJournalModeButtonVisible) {
        LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
        return this.setState({ isCloseJournalModeButtonVisible: true })
      }
    }
  }

  onExpandAllEntries() {
    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
    return this.setState({ expandAllEntries: !this.state.expandAllEntries })
  }

  onCloseJournalMode() {
    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
    return this.props.onCloseJournalMode()
  }

  renderMonthHeader(el) {
    return (
      <View style={styles.sectionListHeaderContainer}>
        <Text style={styles.sectionListHeaderText}>{el.section.title}</Text>
      </View>
    )
  }

  renderMonthEntries(el) {
    return (
      <JournalEntryComponent
        element={el}
        onDisplayDayMoodPress={this.onDisplayDayMoodPress}
        isExpandedFromParent={this.state.expandAllEntries}
        generateSectionListData={this.generateSectionListData}
      />
    )
  }

  render() {
    const hasNotch = DeviceInfo.hasNotch()

    return (
      <View style={styles.contentContainer}>
        <View style={styles.contentContainer}>
          <View style={styles.mainHeaderContainer}>
            <View style={styles.sideHeaderButtonContainer}>
              {hasNotch ? (
                <Text style={styles.mainSideBarTitleText}>
                  {moment().format('Do / M')}
                </Text>
              ) : null}
            </View>

            <View style={styles.mainHeaderTitleContainer}>
              {hasNotch ? null : (
                <Text style={styles.mainHeaderTitleText}>
                  {strings.JournalComponent.journalTitle.title}
                </Text>
              )}
            </View>

            <TouchableOpacity
              style={styles.sideHeaderButtonContainer}
              onPress={this.onExpandAllEntries}
            >
              <Icon
                name={
                  this.state.expandAllEntries ? 'ios-contract' : 'ios-expand'
                }
                style={styles.expandIcon}
              />
            </TouchableOpacity>
          </View>

          <View style={styles.contentContainer}>
            {this.state.sectionListData.length === 0 ? (
              <View style={styles.noDataContainer}>
                <Text style={styles.noEntriesText}>
                  {strings.JournalComponent.noEntries.message1}
                </Text>
                <Text style={styles.noEntriesText}>
                  {strings.JournalComponent.noEntries.message2}
                </Text>
              </View>
            ) : (
              <SectionList
                onMomentumScrollBegin={e =>
                  console.log('onMomentumScrollBegin', e)
                }
                onScroll={this.onHandleScroll}
                stickySectionHeadersEnabled={false}
                renderItem={this.renderMonthEntries}
                renderSectionHeader={this.renderMonthHeader}
                sections={this.state.sectionListData}
                keyExtractor={(item, index) =>
                  `index-${index}-${Math.random() / 100}`
                }
              />
            )}
          </View>
        </View>

        {this.state.isCloseJournalModeButtonVisible ? (
          <TouchableOpacity
            style={styles.closeModalContainer}
            onPress={this.onCloseJournalMode}
          >
            <View style={styles.closeModalIconBorder}>
              <Icon name="ios-close" style={styles.closeModalIcon} />
            </View>
          </TouchableOpacity>
        ) : null}
      </View>
    )
  }
}

export default JournalComponent
class JournalEntryComponent扩展了PureComponent{
建造师(道具){
超级(道具)
如果(Platform.OS==='android'){
UIManager.SetLayoutImationEnabledExperimental&&
UIManager.SetLayoutImationEnabledExperimental(真)
}
this.state={isTextExpanded:false}
this.onExpand=this.onExpand.bind(this)
this.onRegenerateData=this.onRegenerateData.bind(this)
this.deriveColorGradientFromRating=this.deriveColorGradientFromRating.bind(
这
)
}
ondata(){
返回此.props.generateSectionListData()
}
onExpand(){
LayoutImation.configureNext(LayoutImation.Presets.easeInEaseOut)
返回此.setState({isTextExpanded:!this.state.isTextExpanded})
}
deriveColorGradientFromRating(额定值){
//通过查看道具中的设置,决定是显示自定义情绪还是默认情绪
常数{
调色板,
当选,
应该使用默认颜色选项板,
}=this.props.settings.moodColor类别
常量映射到ArrayIndex={[5]:0[4]:1[3]:2[2]:3[1]:4}
如果(!shouldUseDefaultColorPalettes){
//找到正确的自定义调色板并返回带有颜色的数组
让relevantArrayOfGradients=this.props.settings.moodColorCategory[
客户情绪选择
]
让暗色=
相关阵列梯度[Maprating to ArrayIndex[评级]]暗
让颜色变浅=
相关阵列梯度[Maprating to ArrayIndex[额定值]]灯光
返回[浅色,深色]
}
//else从默认调色板返回颜色渐变
返回颜色映射[colorPalette]。颜色映射[rating]。颜色
}
render(){
const{isTextExpanded}=this.state
const{element,isExpandedFromParent,onDisplayDayMoodPress}=this.props
log('isTextExpanded',isTextExpanded)
返回(
{Platform.OS==='ios'(
{element.item.day}
) : (
{element.item.day}
)}
{element.item.data.optionalDescription}
{isTextExpanded(
onDisplayDayMoodPress(element.item.day,element.item.month)
}
>
):null}
)
}
}
常量mapStateToProps=状态=>{
返回{
设置:state.settings,
}
}
导出默认日志组件
父组件:

class JournalEntryComponent extends PureComponent {
  constructor(props) {
    super(props)
    if (Platform.OS === 'android') {
      UIManager.setLayoutAnimationEnabledExperimental &&
        UIManager.setLayoutAnimationEnabledExperimental(true)
    }
    this.state = { isTextExpanded: false }
    this.onExpand = this.onExpand.bind(this)
    this.onRegenerateData = this.onRegenerateData.bind(this)
    this.deriveColorGradientFromRating = this.deriveColorGradientFromRating.bind(
      this
    )
  }

  onRegenerateData() {
    return this.props.generateSectionListData()
  }

  onExpand() {
    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
    return this.setState({ isTextExpanded: !this.state.isTextExpanded })
  }

  deriveColorGradientFromRating(rating) {
    // decide wether to show custom moood or a default mood by looking into settings in props
    const {
      colorPalette,
      customMoodSelected,
      shouldUseDefaultColorPalettes,
    } = this.props.settings.moodColorCategory

    const mapRatingToArrayIndex = { [5]: 0, [4]: 1, [3]: 2, [2]: 3, [1]: 4 }

    if (!shouldUseDefaultColorPalettes) {
      // find the correct custom color palette and return array with colors
      let relevantArrayOfGradients = this.props.settings.moodColorCategory[
        customMoodSelected
      ]

      let darkColor =
        relevantArrayOfGradients[mapRatingToArrayIndex[rating]].dark
      let lightColor =
        relevantArrayOfGradients[mapRatingToArrayIndex[rating]].light

      return [lightColor, darkColor]
    }

    // else return color gradients from default color palettes
    return COLOR_MAP[colorPalette].colorMap[rating].colors
  }

  render() {
    const { isTextExpanded } = this.state
    const { element, isExpandedFromParent, onDisplayDayMoodPress } = this.props

    console.log('isTextExpanded', isTextExpanded)

    return (
      <View style={styles.sectionEntryContainer}>
        <View style={styles.sectionDayContainer}>
          <LinearGradient
            style={styles.gradientDayStyle}
            start={{ x: 0, y: 0 }}
            end={{ x: 1, y: 0 }}
            colors={this.deriveColorGradientFromRating(
              element.item.data.rating
            )}
          >
            {Platform.OS === 'ios' ? (
              <View style={styles.blackLayer}>
                <Text style={styles.sectionDayText} numberOfLines={1}>
                  {element.item.day}
                </Text>
              </View>
            ) : (
              <View style={styles.blackLayerAndroid}>
                <Text style={styles.sectionDayTextAndroid} numberOfLines={1}>
                  {element.item.day}
                </Text>
              </View>
            )}
          </LinearGradient>
        </View>
        <View style={styles.sectionDayDescriptionContainer}>
          <TouchableWithoutFeedback onPress={this.onExpand}>
            <LinearGradient
              style={styles.gradientDescriptionStyle}
              start={{ x: 0, y: 1 }}
              end={{ x: 0, y: 0 }}
              colors={['#d4d5d6', '#eef2f3']}
            >
              <Text
                style={styles.sectionDescriptionText}
                numberOfLines={
                  isTextExpanded || isExpandedFromParent ? null : 2
                }
              >
                {element.item.data.optionalDescription}
              </Text>
            </LinearGradient>
          </TouchableWithoutFeedback>

          {isTextExpanded ? (
            <TouchableOpacity
              style={styles.gradientButtonContainer}
              onPress={() =>
                onDisplayDayMoodPress(element.item.day, element.item.month)
              }
            >
              <LinearGradient
                style={styles.gradientButtonStyle}
                start={{ x: 0, y: 1 }}
                end={{ x: 0, y: 0 }}
                colors={['#d4d5d6', '#eef2f3']}
              >
                <Icon name={'ios-arrow-forward'} style={styles.arrowStyle} />
              </LinearGradient>
            </TouchableOpacity>
          ) : null}
        </View>
      </View>
    )
  }
}

const mapStateToProps = state => {
  return {
    settings: state.settings,
  }
}

export default JournalEntryComponent
class JournalComponent extends PureComponent {
  constructor(props) {
    super(props)
    if (Platform.OS === 'android') {
      UIManager.setLayoutAnimationEnabledExperimental &&
        UIManager.setLayoutAnimationEnabledExperimental(true)
    }

    this.state = {
      sectionListData: [],
      expandAllEntries: false,
      emotionSurveyDateToDisplay: null,
      isShowEmotionSurveyVisible: false,
      isCloseJournalModeButtonVisible: true,
    }

    this.onHandleScroll = this.onHandleScroll.bind(this)
    this.renderMonthHeader = this.renderMonthHeader.bind(this)
    this.renderMonthEntries = this.renderMonthEntries.bind(this)
    this.onExpandAllEntries = this.onExpandAllEntries.bind(this)
    this.onCloseJournalMode = this.onCloseJournalMode.bind(this)
    this.onDisplayDayMoodPress = this.onDisplayDayMoodPress.bind(this)
    this.generateSectionListData = this.generateSectionListData.bind(this)
  }

  componentWillMount() {
    return this.generateSectionListData()
  }

  componentWillReceiveProps(nextProps) {
    if (
      this.props.moods[moment().format('YYYY')] !==
      nextProps[moment().format('YYYY')]
    ) {
      return this.generateSectionListData(
        nextProps.moods[moment().format('YYYY')]
      )
    }
  }

  onHandleScroll(scrollEvent) {
    console.log(scrollEvent.nativeEvent.contentOffset.y)
    if (scrollEvent.nativeEvent.contentOffset.y > height * 2) {
      if (this.state.isCloseJournalModeButtonVisible) {
        LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
        return this.setState({ isCloseJournalModeButtonVisible: false })
      }
    } else if (scrollEvent.nativeEvent.contentOffset.y < height * 2) {
      if (!this.state.isCloseJournalModeButtonVisible) {
        LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
        return this.setState({ isCloseJournalModeButtonVisible: true })
      }
    }
  }

  onExpandAllEntries() {
    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
    return this.setState({ expandAllEntries: !this.state.expandAllEntries })
  }

  onCloseJournalMode() {
    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
    return this.props.onCloseJournalMode()
  }

  renderMonthHeader(el) {
    return (
      <View style={styles.sectionListHeaderContainer}>
        <Text style={styles.sectionListHeaderText}>{el.section.title}</Text>
      </View>
    )
  }

  renderMonthEntries(el) {
    return (
      <JournalEntryComponent
        element={el}
        onDisplayDayMoodPress={this.onDisplayDayMoodPress}
        isExpandedFromParent={this.state.expandAllEntries}
        generateSectionListData={this.generateSectionListData}
      />
    )
  }

  render() {
    const hasNotch = DeviceInfo.hasNotch()

    return (
      <View style={styles.contentContainer}>
        <View style={styles.contentContainer}>
          <View style={styles.mainHeaderContainer}>
            <View style={styles.sideHeaderButtonContainer}>
              {hasNotch ? (
                <Text style={styles.mainSideBarTitleText}>
                  {moment().format('Do / M')}
                </Text>
              ) : null}
            </View>

            <View style={styles.mainHeaderTitleContainer}>
              {hasNotch ? null : (
                <Text style={styles.mainHeaderTitleText}>
                  {strings.JournalComponent.journalTitle.title}
                </Text>
              )}
            </View>

            <TouchableOpacity
              style={styles.sideHeaderButtonContainer}
              onPress={this.onExpandAllEntries}
            >
              <Icon
                name={
                  this.state.expandAllEntries ? 'ios-contract' : 'ios-expand'
                }
                style={styles.expandIcon}
              />
            </TouchableOpacity>
          </View>

          <View style={styles.contentContainer}>
            {this.state.sectionListData.length === 0 ? (
              <View style={styles.noDataContainer}>
                <Text style={styles.noEntriesText}>
                  {strings.JournalComponent.noEntries.message1}
                </Text>
                <Text style={styles.noEntriesText}>
                  {strings.JournalComponent.noEntries.message2}
                </Text>
              </View>
            ) : (
              <SectionList
                onMomentumScrollBegin={e =>
                  console.log('onMomentumScrollBegin', e)
                }
                onScroll={this.onHandleScroll}
                stickySectionHeadersEnabled={false}
                renderItem={this.renderMonthEntries}
                renderSectionHeader={this.renderMonthHeader}
                sections={this.state.sectionListData}
                keyExtractor={(item, index) =>
                  `index-${index}-${Math.random() / 100}`
                }
              />
            )}
          </View>
        </View>

        {this.state.isCloseJournalModeButtonVisible ? (
          <TouchableOpacity
            style={styles.closeModalContainer}
            onPress={this.onCloseJournalMode}
          >
            <View style={styles.closeModalIconBorder}>
              <Icon name="ios-close" style={styles.closeModalIcon} />
            </View>
          </TouchableOpacity>
        ) : null}
      </View>
    )
  }
}

export default JournalComponent
class JournalComponent扩展了PureComponent{
建造师(道具){
超级(道具)
如果(Platform.OS==='android'){
UIManager.SetLayoutImationEnabledExperimental&&
UIManager.SetLayoutImationEnabledExperimental(真)
}
此.state={
sectionListData:[],
expandAllEntries:错误,
emotionSurveyDateToDisplay:null,
isShowEmotionSurveyVisible:假,
isCloseJournalModeButtonVisible:true,
}
this.onHandleScroll=this.onHandleScroll.bind(this)
this.renderMonthHeader=this.renderMonthHeader.bind(this)
this.renderMonthEntries=this.renderMonthEntries.bind(this)
this.onExpandAllEntries=this.onExpandAllEntries.bind(this)
this.onCloseJournalMode=this.onCloseJournalMode.bind(this)
this.ondisplaydemodpress=this.ondisplaydemodpress.bind(this)
this.generateSectionListData=this.generateSectionListData.bind(this)
}
组件willmount(){
返回此值。generateSectionListData()
}
组件将接收道具(下一步){
如果(
this.props.moods[moment().format('YYYY')==
nextProps[moment().format('YYYY')]
) {
返回此值。generateSectionListData(
nextProps.moods[moment().format('YYYY')]
)
}
}
onHandleScroll(滚动事件){
log(scrollEvent.nativeEvent.contentOffset.y)
如果(scrollEvent.nativeEvent.contentOffset.y>height*2){
if(this.state.isCloseJournalModeButtonVisible){
LayoutImation.configureNext(LayoutImation.Presets.easeInEaseOut)
返回此.setState({isCloseJournalModeButtonVisible:false})
}
}else if(scrollEvent.nativeEvent.contentOffset.y<高度*2){
如果(!this.state.isCloseJournalModeButtonVisible){
LayoutImation.configureNext(LayoutImation.Presets.easeInEaseOut)
返回此.setState({isCloseJournalModeButtonVisible:true})
}
}
}
onExpandAllEntries(){
LayoutImation.configureNext(LayoutImation.Presets.easeInEaseOut)
返回此.setState({expandAllEntries:!this.state.expandAllEntries})
}
onCloseJournalMode(){
layoutimation.co