在道具改变时刷新React-Native FlatList - 使用redux来管理状态

时间:2018-05-02 14:16:18

标签: reactjs react-native redux react-redux react-native-flatlist

在您阅读之前 - >>我确实尝试在我的FlatList配置中使用extraData道具,但它似乎无法正常工作(可能是因为我使用Redux来管理状态?)

我的FlatList从我的API呈现数据(基本上它显示用户聊天消息)。

我可以在使用此生命周期方法发送每条聊天消息时刷新FlatList:

    componentDidUpdate(prevProps) {
    if (prevProps.messages !== this.props.messages) {
        this.props.fetchActivityMessages(this.props.navigation.state.params.activityId);
        }
    }

在外面似乎工作正常。但是,这会导致我的服务器发出多个/无限的数据请求。例如,如果我在聊天屏幕上调用console.log(this.props),它会无限地继续调用console.log。

这显然是一个主要问题,但这是我发现使用新数据刷新列表而不必重新加载屏幕的唯一方法。

当我尝试使用extraData prop时,我尝试了以下内容:

extraData={() => {this.props.fetchActivityMessages()}}
extraData={this.props}
extraData={this.props.messages}

无需重新加载页面,无法刷新FlatList。

有人可以帮忙吗?我觉得我在使用componentDidUpdate生命周期方法做错了(导致它产生无限请求)或者我没有正确使用extraData prop。

我的FlatList(聊天)组件

import { activityMessage, sendActivityMessage, fetchActivityMessages } from '../actions';
import ChatListItem from './ChatListItem';

const ROOT_URL = 'https://mydomain.herokuapp.com';
const io = require('socket.io-client/dist/socket.io');
const socket = io.connect(ROOT_URL);


class ActivityChatForm extends Component {

componentDidMount() {
    this.props.fetchActivityMessages(this.props.navigation.state.params.activityId);
}

// Need to fix as it makes infinite requests to the server 
//but so far the only way I could get the FlatList to refresh without reloading page

componentDidUpdate(prevProps) {
    if (prevProps.messages !== this.props.messages) {
        this.props.fetchActivityMessages(this.props.navigation.state.params.activityId);
    }
}

handleSubmit = () => {
    const { activityId } = this.props.navigation.state.params;
    const { sendActivityMessage, messageBody } = this.props;

    socket.emit('createMessage', {
        from: 'MEE!!',
        text: messageBody
    }, (data) => {
        console.log('Received it', data);
      });

      sendActivityMessage({
          activityId,
          messageBody
      });
 }


renderItem = (message) => {
    return <ChatListItem message={message} navigation={this.props.navigation}/>;
}


renderList = () => {
        return (
            <View>
                <FlatList
                    ref={(ref) => { this.flatListRef = ref; }}
                    data={this.props.messages}
                    renderItem={this.renderItem}
                    keyExtractor={(message, index) => index}
                />
            </View>
        );
}


render() {
    return (
        <View>
            <CardSection>
                {this.renderList()}
            </CardSection>

            <CardSection>
                <Input 
                    value={this.props.messageBody}
                    onChangeText={text => this.props.activityMessage({ prop: 'messageBody', value: text})}
                    placeholder="Type your message"
                />
            </CardSection>

            <CardSection>
                <Button                     
                    onPress={() => this.handleSubmit()}
                    buttonText="Send Message"
                />
            </CardSection>
        </View>
    );
  }
}


const mapStateToProps = (state) => {
    const { messageBody } = state.activityMessage;
    const { messages, loading } = state.fetchActivityMessages;

    return { messageBody, messages, loading };
};

export default connect(mapStateToProps, { 
    activityMessage,
    sendActivityMessage,
    fetchActivityMessages
})(ActivityChatForm);

我的ChatListItem组件(用于FlatList中的renderItem)

class ChatListItem extends React.PureComponent {

    render() {
        const { messageBody } = this.props.message.item;

        return (
            <View>
                <CardSection>
                    <Text style={styles.titleStyle}>{ messageBody }</Text>
                </CardSection>      
            </View>
        );
    }
 }

export default ChatListItem;

fetchActivityMessages操作创建者。这用于从我的API中提取用户消息数据

export const fetchActivityMessages = (activityId) => {
    return async (dispatch) => {
        try {
            dispatch({ type: FETCH_MESSAGES_INITIATE });

            let token = await AsyncStorage.getItem('token');

            let { data } = await axios.get(`${ROOT_URL}/activities/${activityId}/chat`, { 
            headers: { 'x-auth': `${token}` } 
        });


            dispatch({ 
                type: FETCH_MESSAGES_SUCCESS,
                payload: data
            });         

    } catch(error) { 
            if (error.response) {
                console.log(error.response.data);
                console.log(error.response.status);
                console.log(error.response.headers);
            } else if (error.request) {
                console.log(error.request);
            } else {
                console.log('Error', error.message);
            }
            console.log(error.config);
        };
    };
};

1 个答案:

答案 0 :(得分:0)

首先摆脱&#34; componentDidUpdate()&#34;。就像你说的那样不断触发。这是因为在屏幕上执行的每个操作,其调用&#34; componentDidUpdate&#34;。

其次,extraData属性需要将状态对象属性传递给它,而不是道具。使用道具它什么都不做。因此,在您的代码中,我认为您需要执行以下操作:

state = {};
 ...
 componentDidMount() {
 const myData = this.props.fetchActivityMessages
              (this.props.navigation.state.params.activityId);
 this.setState({
    data: myData
 })
}

....
<FlatList
 ref={(ref) => { this.flatListRef = ref; }}
 data={this.props.messages}
 extraData={this.state.data}
 renderItem={this.renderItem}
 keyExtractor={(message, index) => index}
/>

我说我想是因为我不确定redux部分。 Redux管理您的应用程序状态,但我认为您仍然可以在各个屏幕中设置状态对象。我不完全确定。我每天都使用React-Native工作,但不是Redux。希望其中一些有用:)