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