#reactjs #react-hooks #use-effect
#reactjs #реагирующие хуки #использование-эффект
Вопрос:
У меня есть список объектов и переменная размера.
const [objectList, setObjectList] = useState([]); //will be filled elsewhere
const [size, setSize] = useState([props.width, props.height]); //might change on user input
useEffect(() => {
//When size changes iterate over objectList
objectList.forEach(object => {
object.set({
width: size.width,
height: size.height
);
});
}, [size]);
Здесь React жалуется, что ObjectList не находится в зависимости, потому что, возможно, я хочу, чтобы useEffect зависел от изменений ObjectList. Однако я этого не делаю. Объекты могут иногда добавляться в список, но в этом случае я устанавливаю размер, в котором объект будет добавлен в список. Я не хочу перебирать каждый объект при добавлении нового объекта в список (список объектов изменен), только при изменении размера.
Как я могу перебирать список объектов при каждом изменении размера, но не при изменении списка объектов?
Ответ №1:
Кажется, есть два действия, влияющие на objectList
: при изменении размера и при добавлении нового объекта.Вам нужно разделить эти два.
Вы можете добиться этого с помощью useReducer
управления различными действиями.
const initialState = {
objectList: []
}
function reducer(state, action) {
switch (action.type) {
case 'ADD_OBJECT': /* TODO */ return;
case 'UPDATE_SIZE': {
const { size } = action.payload;
return state.objectList.map((o) => ({
...o,
width: size.width,
height: size.height
}))
}
default: /* TODO */;
}
}
function App(props) {
const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => {
dispatch({
type: 'UPDATE_SIZE',
payload: {
size: {
width: props.width,
height: props.height
}
}
});
}, [props.size]);
}
Комментарии:
1. Хм, если бы у меня была функция onSizeChanged, я все равно мог бы перебирать список объектов даже без использования редуктора, не так ли? Но это не сработало бы, если бы я хотел, чтобы это было в функции useEffect.
2. Я только что видел ваше недавнее обновление о
props.width
, etc. Обновлено. В любом случае, это анти-шаблон, в котором вы используетеprops.width
, etc в качестве начального состояния, если родительский и дочерний компоненты также обновляют эти реквизиты.3. Хорошо, это было бы возможно, однако есть ли альтернатива? Я не использую useReducer в своем приложении. Потребовалось бы немало усилий по рефакторингу, чтобы изменить все приложение на useReducer. Я извлек пример более абстрактным, потому что я не могу опубликовать здесь весь код приложения.
4. Ну, единственное отличие заключается в том, как обновить
objectList
, который отправляет действие, а не черезsetObjectList
, и доступobjectList
к нему — это просто добавлениеstate
likestate.objectList
. Я не думаю, что это слишком большой рефакторинг, учитывая только два действия, влияющиеobjectList
. Если это так, я чувствую что-то еще.5. Я понимаю, что useReducer, вероятно, является лучшей практикой здесь, и я всегда хотел провести рефакторинг для useReducer, однако я хотел быстро добавить эту функцию, приложение нуждается в некоторой доработке, поскольку я пишу его во время обучения. Это работает так, как сейчас, и требуется рефакторинг, но время сейчас ограничено. Вот почему я хотел посмотреть, могу ли я просто использовать useEffect здесь. Теперь у меня есть обходной путь: я получаю список объектов локально в a
const objects
, но вернусь к вашему ответу, когда у меня будет время для очистки и рефакторинга всего. Следовательно, я проверяю ответ как принятый правильным.