#javascript #reactjs #redux #react-redux
#javascript #reactjs #сокращение #реагировать-redux
Вопрос:
Мой родительский компонент <Room/>
создает дочерние компоненты <RoomSensor/>
, когда родительский компонент создает эти дочерние компоненты, я также отправляю в <RoomSensor/>
uuid, по этому uuid я извлекаю данные датчика из серверной части.
Хранилище — это массив объектов.
// Parent <Room/>
return props.sensors.map((uuid, index) => {
return <RoomSensor key={index} uuid={uuid}/>
})
// Children <RoomSensor/>
const RoomSensor = props => {
useEffect(() => {
console.log("useEffect")
props.fetchSensor(props.uuid)
}, [props.uuid])
console.log(props.sensor)
return (
<div className={"col-auto"}>
<small><b>{props.sensor.value}</b></small>
</div>
)
}
let mapStateToProps = (state, props) => {
return {
sensor: filterSensor(state, props.uuid)
}
}
let mapDispatchToProps = {
fetchSensor,
}
export default connect(mapStateToProps, mapDispatchToProps)(RoomSensor)
// Selectors
export const getSensor = (state, uuid) => {
return _.filter(state.sensors, ["uuid", uuid])[0]
}
export const filterSensor = createSelector(
getSensor,
(sensor) => sensor
)
И я не могу понять двух вещей:
- Когда я делаю обновление, я получаю.
TypeError: Cannot read property 'uuid' of undefined
Я понимаю, что в состоянии еще нет данных, вот почему возникает такая ошибка. Можно ли не отображать компонент до тех пор, пока данные не поступят с сервера?
- Если я комментирую
<small><b>{props.sensor.value}</b></small>
, никаких ошибок не происходит, данные появляются в хранилище, затем я раскомментирую эту строку и вуаля, все работает. Но в консоли я вижу слишком много изменений компонентов. Что я делаю не так? Что-то не так с селектором?
В общем, я хочу, чтобы каждый компонент датчика отображался независимо от других.
Ответ №1:
Следующее основано на нескольких предположениях, полученных из общего кода и выходных данных:
- В настоящее время существует жестко запрограммированный список из 4 идентификаторов UUID датчиков.
createSelector
изreselect
пакета._
ссылается на импортlodash
пакета.
«Возможно ли не отображать компонент до тех пор, пока данные не поступят с сервера?»
Короткий ответ на этот вопрос — да. Для достижения этой цели существует несколько подходов, поэтому вам нужно оценить, что лучше всего соответствует структуре приложения. Вот 2 подхода для рассмотрения:
- Извлеките список датчиков с сервера. Инициализируйте хранилище пустым списком и заполните его после получения данных с сервера.
- В
getSensor
возвращает значение по умолчанию, если uuid отсутствует в списке.
В любом случае, я бы рекомендовал добавить состояние по умолчанию в хранилище. Это поможет уменьшить объем кода, необходимого для обработки граничных случаев.
Вот примерный пример того, как могут выглядеть новые редуктор и селектор для (1):
export const storeReducer = (state, action) => {
let nextState = state;
if (!state) {
// State is uninitialized, so give it a default value
nextState = {
sensors: [],
};
}
switch (action.type) {
case 'RECEIVE_SENSORS':
// We received sensor data, so update the value in the store
nextState = {
...nextState,
sensors: action.sensors,
};
break;
default:
break;
}
return nextState;
};
export const getSensors(state) {
return state.sensors;
}
Действие при получении данных с сервера может выглядеть примерно так:
dispatch({
sensors,
type: 'RECEIVE_SENSORS',
})
«… в консоли я вижу слишком много перезаписанных компонентов [rs]»
Без дополнительного контекста трудно точно сказать, почему происходит повторная визуализация, но наиболее вероятной причиной является то, что каждый вызов props.fetchSensor(props.uuid)
изменяет данные в хранилище (например, если он перезаписывает данные).
Из вывода консоли, которым вы поделились, мы видим, что существует 16 повторных рендерингов, что может произойти из-за:
- Каждый из 4 экземпляров
RoomSensor
вызововfetchSensor
- Это приводит к 4 обновлениям состояния хранилища
- Каждое обновление состояния хранилища заставляет React оценивать каждый экземпляр
RoomSensor
для повторного рендеринга - Следовательно, 4 обновления состояния x 4 оцененных компонента = 16 повторных рендерингов
React довольно эффективен, и если ваш компонент возвращает то же значение, что и при предыдущем запуске, он знает, что не нужно обновлять DOM. Таким образом, влияние на производительность, вероятно, на самом деле не так значительно.
Тем не менее, если приведенная выше теория верна и вы хотите уменьшить количество повторных рендерингов, одним из способов сделать это было бы проверить, совпадают ли данные, которые вы получаете с сервера, с теми, что уже есть в хранилище, и, если да, пропустить обновление хранилища.
Например, fetchSensor
может быть обновлено чем-то вроде:
const existingData = getSensor(getState(), uuid);
const newData = fetch(...);
// Only update the store if there's new data or there's a change
if (!existingData || !_.isEqual(newData, existingData)) {
dispatch(...);
}
Для этого потребуется обновление getSensor
, чтобы вернуть ложное значение (например null
), если uuid не найден в списке датчиков.
Один дополнительный совет
In Room
RoomSensor
отображается с его key
помощью на основе индекса элемента в массиве. Поскольку uuid
должно быть уникальным, вы можете использовать это как key
вместо (т.Е. <RoomSensor key={uuid} uuid={uuid} />
). Это позволило бы реагировать на базовые обновления RoomSensor
только на uuid вместо того, чтобы также учитывать порядок списка.