Использование API context внутри конструктора возможно, вам просто нужно передать его как параметр как в конструктор , так и в метод super , как показано ниже:
export class Child extends React.Component {
static contextTypes = { registerComponent: PropTypes.func };
constructor(props, context) {
super(props, context);
context.registerComponent(props.id);
}
render() {
return <div id={this.props.id} />;
}
}
обновление:
Итак, проблема связана с первым рендерингом на сервере , который не поддерживает взаимодействие, этот подходпредотвратит рассмотрение setState
на сервере , в вашем примере <Provider />
не даст никакой раздачи, поэтому нам нужен обходной путь, который в любом случае будет взломом.
Решение, которое я получил, заключается в наличии нового window.ids
с каждым отслеживаемым компонентом рендеринга (с использованием Head, предоставленного nextjs):
export class Child extends React.Component {
registerComponent = (id) => `
if (window.ids) {
window.ids = [...window.ids, ${id}];
} else window.ids = [${id}];
`;
render() {
return (
<Fragment>
<Head>
<script
className="track"
dangerouslySetInnerHTML={{
__html: `${this.registerComponent(this.props.id)}`,
}}
/>
</Head>
<div id={this.props.id} />
</Fragment>
);
}
}
, поэтому переменная window.ids
будет доступна до <App /> renders
.
здесь есть ссылка на репозиторий для проверки.
еще одно решение может использовать глобальную переменную на сервере, а затем в каждом отслеживаемомкомпонент, который мы могли бы изменить это глобальное изменение, используя componentWillMount ловушка жизненного цикла, поскольку она будет выполняться только на сервере, а затем внедрить эти идентификаторы в HTML-шаблон <head />
, но это возможно, если мы выполняем метод renderToString.
Второе решение : использование страниц / _document вместо страниц / _app , чтобы мы получили доступ к серверу before it renders to string!
:
это ветвь репо: origin / обходной путь-документ
-детский компонент:
export class Child extends React.Component {
render() {
return (
<Fragment>
<Head>
<meta className="track" id={this.props.id} />
</Head>
<div id={this.props.id} />
</Fragment>
);
}
}
-документ (заменяющий приложение):
export default class MyDocument extends Document {
render() {
const { head } = this.props;
const idsFromHead = head.reduce(
(acc, { props }) =>
(props.className.includes('track') && [...acc, props.id]) || acc,
[]
);
return (
<html>
<Head>
<script
dangerouslySetInnerHTML={{
__html: `window.ids=[${idsFromHead}]`,
}}
/>
</Head>
<body className="custom_class">
<h3>{idsFromHead}</h3>
<Main />
<NextScript />
</body>
</html>
);
}
}
этот подходработает на сервере 100%, так как мы можем перехватить отслеживаемые идентификаторы до того, как произойдет повторная отрисовка сервера.
, но <NextScript />
выдает предупреждение (не знаю почему, может быть ошибка из nextjs):