Как получить доступ к функциям дочерних компонентов через ссылки
В документах для React указано, что функции компонента могут быть доступны родительским компонентом через refs. См.: https://facebook.github.io/react/tips/expose-component-functions.html
Я пытаюсь использовать это в своем приложении, но при вызове дочерней функции запускается ошибка "undefined is not a function". Мне интересно, не связано ли это с использованием формата ES6 для классов React, потому что я не вижу других различий между моим кодом и документами.
У меня есть компонент Dialog, который выглядит как следующий псевдокод. Диалог имеет кнопку "Сохранить", которая вызывает функцию save(), которая должна вызвать функцию save() в дочернем компоненте Content. Компонент Content собирает информацию из полей дочерней формы и выполняет сохранение.
class MyDialog extends React.Component {
save() {
this.refs.content.save(); <-- save() is undefined
}
render() {
return (
<Dialog action={this.save.bind(this)}>
<Content ref="content"/>
</Dialog>);
}
}
class Content extends React.Component {
save() {
// Get values from child fields
// and save the content
}
}
Вместо этого я мог бы передать prop (saveOnNextUpdate) до Content и затем выполнить сохранение, когда это правда, но я бы предпочел выяснить, как получить описанный выше метод в React doc выше.
Любые идеи о том, как заставить doc-подход работать или обращаться к дочерней компонентной функции по-другому?
Ответы
Ответ 1
Как оказалось, m90 был прав - это совсем другая проблема. Я отправляю решение на случай, если кто-то столкнется с той же проблемой в будущем.
Мое приложение построено с помощью Redux, и проблема связана с использованием функции connect-redux connect для подключения компонента к хранилищу/глобальному состоянию. По какой-то причине экспорт компонента и подключение его к хранилищу делает невозможным доступ к функциям внутри него. Чтобы обойти это, мне пришлось удалить все использование глобального состояния из Content, чтобы я мог экспортировать его как "немой" компонент.
Чтобы быть более понятным, Content.js выглядел так:
var connect = require('react-redux').connect;
class Content extends React.Component {
save() {
// Get values from child fields
// and save the content
// Use of this.props.stateObject
}
}
function mapStateToProps(state) {
const {
stateObject
} = state;
return {
stateObject
};
}
module.exports = connect(mapStateToProps)(Content);
Удаление использования глобального состояния (и, следовательно, использование connect и mapStateToProps позволило мне экспортировать компонент, используя:
module.exports = Content;
Доступ к this.refs.content.save() магически сработал после этого.
Ответ 2
Redux connect принимает параметр параметра в качестве четвертого параметра. В этом параметре параметра вы можете установить флаг withRef в значение true. Затем вы можете получить доступ к функциям refs, используя getWrappedInstance(). Вот так:
class MyDialog extends React.Component {
save() {
this.refs.content.getWrappedInstance().save();
}
render() {
return (
<Dialog action={this.save.bind(this)}>
<Content ref="content"/>
</Dialog>);
}
}
class Content extends React.Component {
save() { ... }
}
function mapStateToProps(state) { ... }
module.exports = connect(mapStateToProps, null, null, { withRef: true })(Content);
Подробнее об этом читайте здесь: https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options
Стоит прочитать эту статью об использовании ссылок и рассмотреть, если лучше подходит: https://facebook.github.io/react/docs/refs-and-the-dom.html#dont-overuse-refs
Ответ 3
Альтернативный способ сделать это - использовать какое-либо другое имя (кроме ref
). Я обнаружил, что это также хорошо работает, если вы используете библиотеку, такую как styled-components
или emotion
Например, в подключенном MyComponent
:
<MyComponent
...
innerRef={(node) => { this.myRef = node; }}
/>