Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在App shell和SSR中实现同级组件通信_Javascript_Reactjs - Fatal编程技术网

Javascript 如何在App shell和SSR中实现同级组件通信

Javascript 如何在App shell和SSR中实现同级组件通信,javascript,reactjs,Javascript,Reactjs,我采纳了一个建立在这个基础上的项目。该架构采用应用程序外壳和SSR。我正在尝试添加一个简单的搜索栏,这意味着将搜索键从搜索栏组件传递到帖子列表组件,以便对其进行过滤。我发现,对于上下文提供者和消费者来说,这几乎是不可能的。我想使用上下文,但我不知道怎么做。看起来这个初学者工具包有一个严重的缺点,如果能够解决,它将使这个工具包在网上更有用 如果您查看下面的代码和上面的链接,您可以看到有一个标题中心,然后是页面。我需要在页眉和页面之间进行通信。您可以使用链接中的代码添加同级通信 水合物的使用似乎排除

我采纳了一个建立在这个基础上的项目。该架构采用应用程序外壳和SSR。我正在尝试添加一个简单的搜索栏,这意味着将搜索键从搜索栏组件传递到帖子列表组件,以便对其进行过滤。我发现,对于上下文提供者和消费者来说,这几乎是不可能的。我想使用上下文,但我不知道怎么做。看起来这个初学者工具包有一个严重的缺点,如果能够解决,它将使这个工具包在网上更有用

如果您查看下面的代码和上面的链接,您可以看到有一个标题中心,然后是页面。我需要在页眉和页面之间进行通信。您可以使用链接中的代码添加同级通信

水合物的使用似乎排除了上下文提供者的简单应用。Hydrome以并行方式添加组件,而没有办法让上下文提供程序位于这两个组件之上。我在这里使用的模式不起作用。当我更新提供者时,它不会导致上下文使用者的重新呈现

如果我不得不使用上下文以外的东西,比如说Redux,那么我会接受这个答案

以下是客户端入口点:

import { onPageLoad } from 'meteor/server-render';
import MeteorLoadable from 'meteor/nemms:meteor-react-loadable';
import { Switch, Route, Router, Redirect } from 'react-router-dom';
import { ApolloClient } from 'apollo-client';
import { ApolloProvider } from 'react-apollo';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloLink } from 'apollo-link';
import { HttpLink } from 'apollo-link-http';
import { setContext } from 'apollo-link-context';
import { onError } from 'apollo-link-error';
import apolloLogger from 'apollo-link-logger';
import { onTokenChange, getLoginToken } from '/app/ui/apollo-client/auth';
import createBrowserHistory from 'history/createBrowserHistory';
import 'unfetch/polyfill';

// Initialise react-intl
import { primaryLocale, otherLocales } from '/app/intl';

// Need to preload of list of loadable components for MeteorLoadable
import '/app/ui/loadables';

// To get started, create an ApolloClient instance and point it at your GraphQL
// server. By default, this client will send queries to the '/graphql' endpoint
// on the same host.

// To avoid asynchronously accessing local storage for every GraphQL request,
// we cache the authorisation token, and update it using an onTokenChange callback
let authToken;
let authTokenInitialised = false;
onTokenChange(({ token }) => { authToken = token; authTokenInitialised = true; });

const withAuthToken = setContext(() => {
  if (authTokenInitialised) {
    return authToken ? { headers: { authorization: authToken } } : undefined;
  }

  return getLoginToken()
    .then((token) => {
      authToken = token;
      authTokenInitialised = true;
      return authToken ? { headers: { authorization: authToken } } : undefined;
    });
});

const resetAuthToken = onError(({ networkError }) => {
  if (networkError && networkError.statusCode === 401) {
    // Remove cached token on 401 from the server
    authToken = null;
    authTokenInitialised = false;
  }
});

const onErrorLink = onError(({ graphQLErrors, networkError }) => {
  if (graphQLErrors) {
    graphQLErrors.map(({ message, locations, path }) => console.log(
      `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
    ));
  }
  if (networkError) console.log(`[Network error]: ${networkError}`);
});

const client = new ApolloClient({
  link: ApolloLink.from([
    apolloLogger,
    withAuthToken,
    resetAuthToken,
    onErrorLink,
    new HttpLink({
      uri: '/graphql',
    }),
  ]),
  cache: new InMemoryCache().restore(window.__APOLLO_STATE__),
});

// Inject the data into the app shell.
// If the structure's changed, ssr.js also needs updating.
async function renderAsync() {
  const [
    React,
    { hydrate, render },
    { default: App },
    { default: HeaderTitle },
    { default: LanguagePicker },
    { default: Routes },
    { default: Menu },
  ] = await Promise.all([
    import('react'),
    import('react-dom'),
    import('/app/ui/components/smart/app'),
    import('/app/ui/components/smart/header/header-title'),
    import('/app/ui/components/dumb/language-picker'),
    import('/app/ui/routes'),
    import('/app/ui/components/smart/menu'),
    MeteorLoadable.preloadComponents(),
  ]);

  // Given that we are implementing App Shell Architecture and, therefore,
  // injecting (via reactDOM.render) the Header, Menu and Main components into
  // different HTML elements, we need a way to share the router 'history' among
  // all three mentioned components.
  // As a default, for every invocation of 'BrowserRouter', there will be new
  // 'history' instance created. Then, changes in the 'history' object in one
  // component won't be available in the other components. To prevent this, we are
  // relying on the 'Router' component instead of 'BrowserRouter' and defining our
  // custom 'history' object by means of 'createBrowserHistory' function. Said
  // 'history' object is then passed to every invocation of 'Router' and therefore
  // the same 'history' object will be shared among all three mentioned components.

  const history = createBrowserHistory();

  // Inject react app components into App's Shell
  const ClientApp = ({ component }) => (
    <Router history={history}>
      <ApolloProvider client={client}>
        <Switch>
          {/* Map our locales to separate routes */}
          { otherLocales.map(locale => (
            <Route
              key={locale}
              path={`/${locale}/`}
              render={props => <App component={component} {...props} locale={locale} section="app" />}
            />
          ))}

          { primaryLocale && (
            <Route
              key={primaryLocale}
              path="/"
              render={props => <App component={component} {...props} locale={primaryLocale} section="app" />}
            />
          )}

          {/* If no valid locale is given, we redirect to same route with the preferred locale prefixed */}
          <Route render={({ location }) => <Redirect to={`/${window.__PREFERRED_LOCALE__ || otherLocales[0]}${location.pathname}`} />} />
        </Switch>
      </ApolloProvider>
    </Router>
  );

  render(<ClientApp component={Menu} />, document.getElementById('menu'));

  hydrate(<ClientApp component={HeaderTitle} />, document.getElementById('header-title'));
  hydrate(<ClientApp component={LanguagePicker} />, document.getElementById('header-lang-picker'));

  hydrate(<ClientApp component={Routes} />, document.getElementById('main'));
}

onPageLoad(() => {
  const renderStart = Date.now();
  const startupTime = renderStart - window.performance.timing.responseStart;
  console.log(`Meteor.startup took: ${startupTime}ms`);

  // Register service worker
  import('/app/ui/register-sw').then(() => {});

  renderAsync().then(() => {
    const renderTime = Date.now() - renderStart;
    console.log(`renderAsync took: ${renderTime}ms`);
    console.log(`Total time: ${startupTime + renderTime}ms`);
  });
});
从'meteor/server render'导入{onPageLoad};
从“meteor/nemms:meteor react loadable”导入MeteorLoadable;
从“react Router dom”导入{交换机、路由、路由器、重定向};
从“apollo客户端”导入{apollo客户端};
从'react apollo'导入{ApolloProvider};
从'apollo cache inmemory'导入{InMemoryCache};
从“阿波罗链接”导入{apollo链接};
从“阿波罗链接http”导入{HttpLink};
从“阿波罗链接上下文”导入{setContext};
从“阿波罗链接错误”导入{onError};
从“阿波罗链接记录器”导入阿波罗记录器;
从'/app/ui/apollo-client/auth'导入{onTokenChange,getLoginToken};
从“历史记录/createBrowserHistory”导入createBrowserHistory;
导入“未蚀刻/聚填充”;
//初始化react intl
从'/app/intl'导入{primaryLocale,otherLocales};
//需要为可加载组件预加载可加载组件列表
导入“/app/ui/loadables”;
//首先,创建一个Apollo客户端实例并将其指向GraphQL
//服务器。默认情况下,此客户端将向“/graphql”端点发送查询
//在同一主机上。
//为了避免对每个GraphQL请求异步访问本地存储,
//我们缓存授权令牌,并使用onTokenChange回调更新它
让authonk;
让AuthTokenInitialized=false;
onTokenChange(({token})=>{authToken=token;AuthTokenInitialized=true;});
const withAuthToken=setContext(()=>{
如果(已初始化){
返回authToken?{头:{授权:authToken}}:未定义;
}
返回getLoginToken()
。然后((令牌)=>{
authToken=令牌;
AuthTokenInitialized=true;
返回authToken?{头:{授权:authToken}}:未定义;
});
});
const resetAuthToken=onError({networkError})=>{
if(networkError&&networkError.statusCode==401){
//从服务器中删除401上的缓存令牌
authToken=null;
AuthTokenInitialized=false;
}
});
const onErrorLink=onError({graphQLErrors,networkError})=>{
如果(图形错误){
graphQLErrors.map({message,locations,path})=>console.log(
`[GraphQL错误]:消息:${Message},位置:${locations},路径:${Path}`,
));
}
if(networkError)console.log(`[networkError]:${networkError}`);
});
const客户端=新客户端({
链接:ApolloLink.from([
阿波罗记录器,
使用AuthToken,
重置AuthToken,
onErrorLink,
新HttpLink({
uri:“/graphql”,
}),
]),
缓存:新建InMemoryCache().restore(窗口).\uuu APOLLO\u STATE\uuuuuu),
});
//将数据注入应用程序外壳。
//如果结构发生变化,ssr.js也需要更新。
异步函数renderAsync(){
常数[
反应
{水合物,渲染},
{default:App},
{default:HeaderTitle},
{default:LanguagePicker},
{default:Routes},
{默认:菜单},
]等待承诺([
导入('react'),
导入('react-dom'),
导入('/app/ui/components/smart/app'),
导入('/app/ui/components/smart/header/header title'),
导入('/app/ui/components/dumb/language picker'),
导入('/app/ui/routes'),
导入('/app/ui/components/smart/menu'),
MeteorLoadable.preloadComponents(),
]);
//鉴于我们正在实施应用程序外壳架构,因此,
//将标题、菜单和主要组件(通过reactDOM.render)注入到
//不同的HTML元素,我们需要一种方法来共享路由器的“历史”
//上述三个组成部分。
//默认情况下,每次调用“BrowserRouter”都会有新的
//创建了“history”实例。然后,在一个实例中更改“history”对象
//组件在其他组件中不可用。为防止此情况,我们
//依赖“路由器”组件而不是“浏览器路由器”,并定义
//通过“createBrowserHistory”函数自定义“history”对象
//然后将“历史”对象传递给“路由器”的每次调用,因此
//上述三个组件将共享同一个“历史”对象。
const history=createBrowserHistory();
//将react应用程序组件注入应用程序外壳
常量ClientApp=({component})=>(
{/*将我们的地区映射到不同的路线*/}
{otherLocales.map(locale=>(
}
/>
))}
{primaryLocale&&(
}
/>
)}
{/*若并没有给出有效的语言环境,我们将重定向到带有首选语言环境前缀的相同路由*/}
} />
);
render(,document.getElementById('menu'));
水合物(,document.getElementById('header-title'