Я бы подошел к вашему варианту использования таким образом, чтобы получить лучшее из обоих решений.
Прежде всего, отправив много действий, вы беспокоитесь о рендеринге. Используя библиотеку селектора, скажем, перевыберите , запоминание библиотеки предотвратит ненужную перерисовку компонентов.
Позже, если я вас правильно понял, ваша цель - дать серверу знать статус видимости элемента (концерта) и, в конечном итоге, его видимое время. Если ваша цель - уведомить сервер только , не сообщая интерфейсным пользователям остальных приложений, почему вы хотите отслеживать его и в Redux? Вы можете пропустить часть Redux и отправлять обновления только на сервер.
Предположим, вам нужен Redux для отслеживания. Вы можете попытаться структурировать Store, как вы уже упоминали, добавив флаг visible
к каждому объекту в хранилище Redux. Но если структура ваших элементов достаточно велика, и копирование и обновление объекта каждый раз при изменении флага visible
обходится дорого, вы можете рассмотреть вопрос о создании выделенной ветви и редуктора магазина, которая будет отвечать только за потребности в отслеживании. Примерно так:
tracking : {
concerts: {
1: { visible: true, time: 10 }
}
}
Теперь, обновляя флаг предмета, нужно скопировать и изменить только указанную выше крошечную структуру. Даже вы можете сделать его меньше и конкретнее для определенного типа предмета (trackingConcerts
).
* Имейте в виду, вы сами решаете, будет ли такая специализированная ветвь Магазина улучшать производительность, потому что мы не знаем вашей подробной архитектуры и особенностей Магазина.
Продолжая с решениями ...
Как вы упомянули, использование навигационных действий + промежуточное программное обеспечение подвержено ошибкам. Как насчет варианта использования, у вас есть общая страница компонентов (то есть будет отправлено действие навигации с общим именем), но вы представите там один из ваших элементов (концерт)? Кроме того, рендеринг элемента всегда будет сопровождаться изменением логики сопоставления в вашем промежуточном программном обеспечении или там, где вы отслеживаете элементы по имени действия. Другой сложный случай - когда вы отображаете различные типы элементов (концерты, места проведения) на одной странице. Как вы будете различать и отслеживать элементы, учитывая, что у вас есть только 1 элемент навигации? Также в такой настройке я не вижу простого способа обработки видимого времени элемента.
О селекторах как о решении - они могут быть лишь малой частью решения. Селектор отвечает за выбор и управление производным состоянием. Ничего больше.
Покажите мне код, пожалуйста.
Я бы создал компонент-оболочку вокруг , реагировал бы на экран (или любую подобную библиотеку, которая отслеживает видимость компонента) и реализовывал только отслеживание видимого времени компонента.
Оболочка будет вызывать обратные вызовы при изменении состояния видимости компонента и обратный вызов на componentDidUnmount
, включая видимое время.
Вот и все! Теперь вы можете прикреплять обработчики к этим обратным вызовам и обновлять Redux и / или уведомлять сервер об изменениях видимости, не полагаясь на какие-либо действия по навигации и промежуточное ПО.
Использование:
const App = () => (
<Tracking
onVisibilityChange={isVisible => {}}
onUnmount={visibleSeconds => {}}
>
<Concert id={1} />
</Tracking>
)
Оболочка отслеживания:
import TrackVisibility from 'react-on-screen'
const Tracking = ({ children, libraryProps, ...rest }) => (
<TrackVisibility {...libraryProps}>
<TrackingCore {...rest}>
{children}
</TrackingCore>
</TrackVisibility>
)
TrackingCore, наша пользовательская логика отслеживания:
class TrackingCore extends React.Component {
constructor (props) {
super(props)
this.state = {
visibleSeconds: 0,
interval: null
}
}
componentDidMount() {
this.track()
}
componentWillReceiveProps (nextProps) {
this.track(nextProps)
}
componentDidUnmount() {
const { visibleSeconds, interval } = this.state
const { onUnmount } = this.props
onUnmount(visibleSeconds)
clearInterval(interval)
}
track (nextProps) {
const { isVisible, onVisibilityChange } = this.props
const { visibleSeconds, interval } = this.state
const hasVisibilityChanged = (isVisible !== nextProps.isVisible) || !nextProps
const isVisibleValue = nextProps ? nextProps.isVisible : isVisible
// On visibility change, invoke the callback prop
if (hasVisibilityChanged) {
onVisibilityChange(isVisibleValue)
// If it becomes visible, start counting the `visibleSeconds`
if (isVisibleValue) {
this.setState({
interval: setInterval(() => this.setState({
visibleSeconds: visibleSeconds + 1
}), 1000)
})
} else {
clearInterval(interval)
}
}
}
render () {
return this.props.children
}
}