Лучший способ использовать условное выражение для useContext в React?

#reactjs #react-hooks #use-context

#reactjs #реагирующие хуки #использовать-контекст

Вопрос:

У меня есть CommonChild компонент, который вызывается в двух компонентах: Parent1 и Parent2 .

Жирный Parent1 и Parent2 используется по-разному AppContext .

Пожалуйста, посмотрите простой код ниже:

 import React, { useState, useContext, createContext } from 'react'

//Create two createContext of Parents
const ContextParent1 = createContext();
const ContextParent2 = createContext();

//Create two providers of Parents
const AppProviderParent1 = (props) => {
    const [state] = useState("This is AppProviderParent1")
    return (
        <ContextParent1.Provider value={state}>
            {props.children}
        </ContextParent1.Provider>
    )
}
const AppProviderParent2 = (props) => {
    const [state] = useState("This is AppProviderParent2")
    return (
        <ContextParent2.Provider value={state}>
            {props.children}
        </ContextParent2.Provider>
    )
}

//Two parents called CommonChild, but different AppProvider (created above)
const Parent1 = (props) => {
    return (
        <AppProviderParent1 {...props}>
            <CommonChild />
        </AppProviderParent1>
    )
}
const Parent2 = (props) => {
    return (
        <AppProviderParent2 {...props}>
            <CommonChild />
        </AppProviderParent2>
    )
}

//CommonChild that try to use useContext to get value
const CommonChild = () => {
    const context = useContext(...) //how to use useContext?
    return (
        <p>This is CommonChild Component</p>
    )
}
  

Я не знаю, как разумно использовать useContext в CommonChild which.

Спасибо за вашу помощь

Комментарии:

1. Вы создаете единый контекст const MyContext = createContext(<Default value here>); , а затем создаете поставщиков для контекста в каждом из ваших родителей, изменяя value предоставляемое вами свойство. Затем вы используете контекст в дочернем элементе путем вызова const context = useContext(MyContext) , и он получит наиболее релевантный родительский контекст или значение по умолчанию, если родительский контекст не найден.

2. Ох. Вы имеете в виду, что оба AppProviderParent1 и AppProviderParent2 могут использовать одно и то же createContext ?

3. Да, если нет разницы между свойствами, которые они содержат. т.Е. Родительский элемент 1 может предоставлять значения { propA: true} , а родительский элемент 2 может предоставлять значения поставщика { propA: false}

4. Я попробую. Спасибо

5. Вот пример https://stackblitz.com/edit/react-ts-jheevm?file=index.tsx . Примечание: используется typescript

Ответ №1:

Способ 1

Вы можете передать идентификатор CommonChild , который сообщает, кто его вызывает. Затем используйте условную операцию ? следующим образом-

 const Parent1 = (props) => {
    return (
        <AppProviderParent1 {...props}>
             
            {/********** Pass down the caller string **********/}
            <CommonChild caller='parent1' />
        </AppProviderParent1>
    )
}
const Parent2 = (props) => {
    return (
        <AppProviderParent2 {...props}>
            
        {/********** Pass down the caller string **********/}
            <CommonChild caller='parent2' />
        </AppProviderParent2>
    )
}

//CommonChild that try to use useContext to get value
const CommonChild = ({caller}) => {
    const context = 
        caller === useContext('parent1' ?  AppProviderParent1 : AppProviderParent2);
    return (
        <p>This is CommonChild Component</p>
    )
}
  

Способ 2

Как вы указали в комментарии, у вас также есть несколько контекстов и дочерних элементов. Для этого вы можете поместить все контексты в массив и передать число дочернему компоненту, указывающему индекс используемого контекста.

 const appProviders = [AppProviderParent1, AppProviderParent2];

const Parent1 = (props) => {
    return (
        <AppProviderParent1 {...props}>
             
            {/********** Pass down index of AppProvider **********/}
            <CommonChild providerIndex='1' />
        </AppProviderParent1>
    )
}
const Parent2 = (props) => {
    return (
        <AppProviderParent2 {...props}>
            
        {/********** Pass down index of AppProvider **********/}
            <CommonChild providerIndex='2' />
        </AppProviderParent2>
    )
}


const CommonChild = ({providerIndex}) => {

// Remember to subtract 1 from providerIndex
    const context = 
        caller === useContext(AppProviders[providerIndex - 1];
    return (
        <p>This is CommonChild Component</p>
    )
}
  

Таким образом, вы можете передать соответствующий контекст любому дочернему элементу, который вы хотите.

Комментарии:

1. Мне это не нравится, потому что у меня много дочерних элементов, используемых в обоих родительских компонентах