У меня есть следующее в ответном собственном приложении:
export default function MyScreen() {
const componentRefs = useRef([]);
return (
<View >
{myArray.map(
(wc, index) =>
(
<MyObject
key = {index}
ref = {el => componentRefs.current[index] = el}
index = {index}
// other props
/>
)
)}
</View>
);
}
Каждый экземпляр MyObject отображает слово. Хочу добавить функционал, который будет при нажатии кнопки выделять по очереди каждое слово и воспроизводить аудиофайл с его произношением.
Для этого мне нужно сохранить ссылку на каждый экземпляр MyObject в родительской функции MyScreen, чтобы впоследствии можно было просмотреть все отображаемые слова.
Моя первоначальная попытка — использовать useRef для создания массива для хранения ссылок, как показано выше.
В качестве первоначального теста у меня есть обработчик кнопок, который проверяет, сохранены ли ссылки. Это просто перебирает каждый элемент в componentRefs:
componentRefs.current.forEach((x) => console.info(x));
Однако ничего не отображается. Также есть предупреждение:
Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Как лучше всего хранить ссылки в родительском элементе, чтобы обеспечить желаемую функциональность?
Большое спасибо
Доступ к дочерним компонентам из родительского обычно является антишаблоном. Скорее всего, вы можете передать обратные вызовы и/или идентификаторы или использовать контекст для доступа к общему состоянию.
@Конрад, ты можешь объяснить?
компонентRefs.current.forEach((x) => console.info(x)); ничего не выводит на консоль
Вы должны передать функцию журнала в качестве опоры каждому дочернему элементу, и они позаботятся о вызове.
@user1052610 user1052610 Он ничего не регистрирует, потому что массив пуст. Ты никогда ничего туда не кладешь. componentRefs[index] = <-- видишь... ? Я также хотел бы повторить, что это полный антипаттерн, и «решение этого» только создаст для вас больше проблем, поскольку вы пытаетесь заставить что-то вести себя так, как вы хотите, вместо того, чтобы научиться на самом деле использовать это.
Спасибо. Как правильно это сделать? Если бы вы могли показать это в ответе, это было бы очень признательно.
Как я уже говорил: передайте обратный вызов и/или идентификатор или используйте контекст для общего состояния. Я не могу дать более конкретный ответ, поскольку вы опустили все детали, кроме того факта, что вы хотите поместить данные в массив из useRef. В общем, вы не хотите получать доступ к дочерним элементам от родителя. Вы хотите передавать вещи только вниз по иерархии. Я понятия не имею, какой у вас вариант использования.
Почитайте, что такое проблема XY.
Спасибо - отредактирую вопрос, чтобы лучше объяснить
Не следует редактировать стили, используя ссылку. Вы должны создать состояние и изменить состояние





Пожалуйста, попробуйте использовать приведенный ниже код:
export default function App() {
const componentRefs = useRef([]);
useEffect(() => {
Object.keys(componentRefs).map((item, i) => console.info(componentRefs[item]))
}, [componentRefs]);
return (
<View>
{myArray.map(
(wc, index) =>
(componentRefs[index] = (
<MyObject
key = {index}
index = {index}
// other props
/>
))
)}
</View>
);
}
При использовании компонентаRefs.current.forEach ошибок нет, но ничего не отображается. При регистрации определенного элемента выводится сообщение «не определено».
можешь ли ты описать, что внутри MyObject?
также получите предупреждение: функциональным компонентам нельзя давать ссылки. Попытки получить доступ к этой ссылке потерпят неудачу. Вы имели в виду использовать React.forwardRef()?
@user1052610 user1052610 Я отредактировал ответ, пожалуйста, просмотрите его.
Это правильно регистрируется один раз (в useEffect), но не в обработчике кнопки, используя bcomComponentRefs.current.forEach((x) => console.info(x));
Принял этот ответ, большое спасибо. Остается одна проблема: как очистить массив компонентных ссылок. компонентRefs.current=[] и компонентRefs.current.length=0 не работают.
Используйте этот пример кода, чтобы использовать внутренний цикл useRef. Это всего лишь пример, меняйте компоненты по своему усмотрению.
export default function MyScreen() {
const componentRefs = useRef([]);
useEffect(() => {
componentRefs.current.forEach(el => console.info(el));
}, [componentRefs]);
return (
<div>
{myArray.map(
(wc, index) => (
<MyObject
key = {index}
index = {index}
componentRefs = {componentRefs}
// other props
/>
)
)}
</div>
);
}
const MyObject = ({ index, componentRefs }) => {
const ref = useRef(null);
componentRefs.current[index] = ref;
return (
<View ref = {ref}>
children
</View>
)
}
@user1052610 user1052610 Я снова отредактировал ответ. Теперь он должен предоставить вам все элементы внутри компонента Refs.current.
componentRefs.current.forEachно зачем тебе это нужно? Вы неправильно используете ссылку