如何让组件知道调用组件的上下文?

huangapple go评论53阅读模式
英文:

How to let component know which context calls the component?

问题

假设我有一个组件和两个上下文。两个上下文都可以使用这个组件。当context1使用它时,组件应在自身中执行const context = useContext(Context1)。当context2使用它时,组件应在自身中执行const context = useContext(Context2)。但这个组件如何知道现在是哪个上下文在使用它并执行相应的操作呢?

好的,我将提供一个简单的示例,但实际情况比这更复杂,例如,Common 组件被多次包装,而这两个组件看起来不同。

通用组件

export default function Common(){
  const context = useContext(/*其中一个上下文*/);
  context.setData(newData);
  return (
     <div>{context.data}</div>
  )
}

组件1

export const Context1 = createContext({ data, setData });

export default function Component1() {
  <Context1.Provider value={{data, setData }}>
     <Common />
  </Context1.Provider>
}

组件2

export const Context2 = createContext({ data, setData  });

export default function Component2() {
  <Context2.Provider value={{data, setData }}>
     <Common />
  </Context2.Provider>
}
英文:

Suppose I have a component and two contexts. The both contexts can use this component. When context1 uses it, the component should do const context=useContext(Context1) in itself. When context2 uses it, the component should do const context=useContext(Context2) in itself. But how can this component know which context is using it now and do the instuction?

OK, I will give an easy example of it but the real situation is more complex than it, for example, Common is wrapped many times and the two components look different.

The common component

export default function Common(){
  const context=useContext(/*one of the context*/);
  context.setData(newData);
  return (
     <div>{context.data}</div>
  )
}

Component1

export const Context1 = createContext({ data, setData });

export default function Component1() {
  <Context1.Provider value={{data, setData }}>
     <Common />
  </Context1.Provider>
}

Component2

export const Context2 = createContext({ data, setData  });

export default function Component2() {
  <Context2.Provider value={{data, setData }}>
     <Common />
  </Context2.Provider>
}

答案1

得分: 2

以下是您要翻译的内容:

如果您有一个必须选择要使用哪个上下文的组件,我认为您应该重新思考您的设计。如果您能解释这两个上下文是什么以及组件如何使用它们,那将更容易帮助您,但似乎您不愿详细说明。

是否有某种原因您不能有一个单一的上下文,其“值”会发生变化,而不是完全分开的上下文?我想我永远不会知道了。

如果您坚持要有两个上下文并让您的组件在它们之间进行选择,您可以有一个指定要使用哪个上下文的上下文。

const Context1 = React.createContext("我是上下文一!");
const Context2 = React.createContext("我是上下文二!");

const WhichContext = React.createContext(Context1);

function MyComponent() {
  const which = React.useContext(WhichContext);
  const context = React.useContext(which);
  
  return (
    <div>{context}</div>
  );
}

function App () {
  return (
    <WhichContext.Provider value={Context2}>
      <MyComponent />
    </WhichContext.Provider>
  );
}

const root = ReactDOM.createRoot(document.getElementById('app'));
root.render(<App />);

您也可以将其作为一个属性传递:

const Context1 = React.createContext("我是上下文一!");
const Context2 = React.createContext("我是上下文二!");

const WhichContext = React.createContext(Context1);

function MyComponent(props) {
  const context = React.useContext(props.context);
  
  return (
    <div>{context}</div>
  );
}

function App () {
  return (
    <MyComponent context={Context2} />
  );
}

const root = ReactDOM.createRoot(document.getElementById('app'));
root.render(<App />);

这些是您要求的翻译内容,不包含代码部分。

英文:

If you've got a component that has to choose which context to use I think you should rethink your design. It would be much easier to help if you would explain what the two contexts are and what the component is doing with them, but you don't seem willing to elaborate.

Is there a reason you can't have a single context whose value changes, instead of entirely separate contexts? I guess I'll never know.

If you insist on having two contexts and making your component choose between them you could have a context that specifies which context to use.

<!-- begin snippet: js hide: false console: true babel: true -->

<!-- language: lang-js -->

const Context1 = React.createContext(&quot;I&#39;m context one!&quot;);
const Context2 = React.createContext(&quot;I&#39;m context two!&quot;);

const WhichContext = React.createContext(Context1);

function MyComponent() {
  const which = React.useContext(WhichContext);
  const context = React.useContext(which);
  
  return (
    &lt;div&gt;{context}&lt;/div&gt;
  );
}

function App () {
  return (
    &lt;WhichContext.Provider value={Context2}&gt;
      &lt;MyComponent /&gt;
    &lt;/WhichContext.Provider&gt;
  );
}

const root = ReactDOM.createRoot(document.getElementById(&#39;app&#39;));
root.render(&lt;App /&gt;);

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;


&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

You could also just pass it in as a prop:

<!-- begin snippet: js hide: false console: true babel: true -->

<!-- language: lang-js -->

const Context1 = React.createContext(&quot;I&#39;m context one!&quot;);
const Context2 = React.createContext(&quot;I&#39;m context two!&quot;);

const WhichContext = React.createContext(Context1);

function MyComponent(props) {
  const context = React.useContext(props.context);
  
  return (
    &lt;div&gt;{context}&lt;/div&gt;
  );
}

function App () {
  return (
      &lt;MyComponent context={Context2} /&gt;
  );
}

const root = ReactDOM.createRoot(document.getElementById(&#39;app&#39;));
root.render(&lt;App /&gt;);

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;


&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

答案2

得分: 1

你可以尝试在本地存储中存储一些键值,然后从组件中获取该值。

例如,在context1中只需添加一行:

localStorage.setItem('currentcontext', 'context1');

而在context2中:

localStorage.setItem('currentcontext', 'context2');

然后在组件加载时,只需从本地存储中检索该值:

var current = localStorage.getItem('currentcontext');

然后,你将在名为"current"的变量中存储当前使用的上下文名称。

我尝试根据我理解的问题程度来回答,如果你遇到其他问题,请留言。

英文:

You can try making storing some key value in the local storage and get the value in the component from there .

like in context1 just add one line

localStorage.setItem(&#39;currentcontext&#39;, &#39;context1&#39;);

and in context2 be

localStorage.setItem(&#39;currentcontext&#39;, &#39;context2&#39;);

now then your component loads just retrive the value from the clocalstorage by

var current = localStorage.getItem(&#39;currentcontext&#39;);

then you will have the currently used context name stored in current named variable..

i tried to answer based on how much i came to get your problem if you face any other issue do comment...

答案3

得分: 1

当我同意这样做的需要可能是对React设计的误解时,应该不需要;而_ray_的答案似乎更符合"React方式"和更优雅...我将提供另一种选项。

您可以在默认Context值中添加一些标志或信息,以定义Context是否实际可用:

const Context1 = createContext({available: false})

const Component = () => {
   const context1 = useContext(Context1)
   console.log(context1.available)
   return <div />
}
<Component /> // <-- 将打印 "false"
<Context1.Provider value={{available: true}}>
  <Component /> // <-- 将打印 "true"
</Context1.Provider>

编辑,更清楚地适用于您的两个上下文的特定用法:

const Context1 = createContext({available: false, /* 您的其他Context1默认值 */})
const Context2 = createContext({available: false, /* 您的其他Context2默认值 */})

const Component = () => {
   const context1 = useContext(Context1)
   const context2 = useContext(Context2)
   if(context1.available) {
      console.log("Context1 可用,根据需要使用它")
   } else if(context2.available) {
      console.log("Context2 可用,根据需要使用它")
   } else {
      console.error("未找到context1或context2!!")
   }
   return <div />
}
<Context1.Provider value={{available: true, /* 其他context1值 */}}>
  <Component />
</Context1.Provider>
<Context2.Provider value={{available: true, /* 其他context2值 */}}>
  <Component />
</Context2.Provider>

当然,如果上下文是"嵌套"的话,这是无法帮助的。

英文:

While I agree that the need to do this is probably a missunderstand of React design, should be not needed; and while ray answer seems more "React way" and elegant... I will give another option.

You could add some flag or info in the default Context values that define if the Context is actually available:

const Context1 = createContext({available: false})

const Component = () =&gt; {
   const context1 = useContext(Context1)
   console.log(context1.available)
   return &lt;div /&gt;
}
&lt;Component /&gt; // &lt;-- will print &quot;false&quot;
&lt;Context1.Provider value={{available: true}}&gt;
  &lt;Component /&gt; // &lt;-- will print &quot;true&quot;
&lt;/Context1.Provider&gt;

Edit, more clearly for your specific use with two contexts:

const Context1 = createContext({available: false, /* your other Context1 default values */})
const Context2 = createContext({available: false, /* your other Context2 default values */})

const Component = () =&gt; {
   const context1 = useContext(Context1)
   const context2 = useContext(Context2)
   if(context1.available) {
      console.log(&quot;Context1 is available, use it as needed&quot;)
   } else if(context2.available) {
      console.log(&quot;Context2 is available, use it as needed&quot;)
   } else {
      console.error(&quot;No context1 or context2 found!!&quot;)
   }
   return &lt;div /&gt;
}
&lt;Context1.Provider value={{available: true, /* other context1 values */}}&gt;
  &lt;Component /&gt;
&lt;/Context1.Provider&gt;
&lt;Context2.Provider value={{available: true, /* other context2 values */}}&gt;
  &lt;Component /&gt;
&lt;/Context2.Provider&gt;

Of course, this won't help if the contexts are "nested".

huangapple
  • 本文由 发表于 2023年6月2日 12:43:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76387176.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定