Обновление React-Native FlatList при смене реквизита - использование избыточности для управления состоянием - PullRequest
0 голосов
/ 02 мая 2018

Перед прочтением - >> Я попытался использовать реквизиты extraData в моей конфигурации FlatList, но, похоже, он не работает должным образом (возможно, потому что я использую 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, я попытался сделать следующее:

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

Ничто из этого не привело к обновлению FlatList без перезагрузки страницы.

Кто-нибудь может помочь? Я чувствую, что либо делаю что-то не так с методом жизненного цикла componentDidUpdate (вызывая бесконечные запросы), либо неправильно использую опцию extraData.

Мой компонент FlatList (Chat)

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)

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 голосов
/ 02 мая 2018

Сначала избавьтесь от "componentDidUpdate ()". Как вы сказали, это срабатывает постоянно. Это связано с тем, что при каждом действии, выполняемом на экране, оно вызывает «componentDidUpdate».

Во-вторых, для атрибута 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 управляет состоянием ваших приложений, но я думаю, что вы все равно можете устанавливать объекты состояния на отдельных экранах. Опять же я не совсем уверен. Мы ежедневно используем React-Native, где я работаю, но не Redux. Надеюсь, что это поможет:)

...