자식 구성 요소 내부에서 React Context를 업데이트하는 방법은 무엇입니까?


109

다음과 같이 컨텍스트에 언어 설정이 있습니다.

class LanguageProvider extends Component {
  static childContextTypes = {
    langConfig: PropTypes.object,
  };

  getChildContext() {
    return { langConfig: 'en' };
  }

  render() {
    return this.props.children;
  }
}

export default LanguageProvider;

내 응용 프로그램 코드는 다음과 같습니다.

<LanguageProvider>
  <App>
    <MyPage />
  </App>
</LanguageProvider>

내 페이지에 언어 전환을위한 구성 요소가 있습니다.

<MyPage>
  <LanguageSwitcher/>
</MyPage>

LanguageSwitcherMyPage상황에서 아래와 같이 언어를 'jp'로 변경하기 위해 컨텍스트를 업데이트해야합니다.

class LanguageSwitcher extends Component {
  static contextTypes = {
    langConfig: PropTypes.object,
  };

  updateLanguage() {
    //Here I need to update the langConfig to 'jp' 
  }

  render() {
    return <button onClick={this.updateLanguage}>Change Language</button>;
  }
}

export default LanguageSwitcher;

LanguageSwitcher 구성 요소 내에서 컨텍스트를 업데이트하려면 어떻게해야합니까?


읽어 보셨나요? facebook.github.io/react/docs/context.html#updating-context 아마도이 더 잘 상태없는 상황에 적합 무언가이다
azium

@azium 예 .. 해당 문서에서 컨텍스트는 구성 요소 자체에서 업데이트되거나 컨텍스트 공급자에게 전달 된 컨텍스트가 포함 된 문서에 추가 된 블로그 링크가 있습니다. 자식 구성 요소에서 업데이트해야합니다
mshameer

문서를 업데이트해야 할 경우 컨텍스트를 사용하지 말라고합니다. 정확히 말하면 "하지 마십시오". 나는, 사용 상태없는 상황 반복합니다
azium

2
@LondonRob 어떤 종류의 정식 답변을 찾고 있습니까? IMO 문서의 내용은 나에게 잘 보입니다. 자식에서 컨텍스트를 설정하려면 공급자의 구성 요소에 setter를 만들고 자식 소비자에게 전달하면됩니다. 그런 다음 하위 소비자에서 해당 setter를 호출하고 하위에있는 데이터로 설정합니다. 데이터를 올리는 React의 아이디어를 계속 유지합니다.
Andrew Li

2
@azium은 몇 년 후이 댓글을 읽는 다른 사람들에게 알려줍니다. 이제 하위 구성 요소에서 컨텍스트를 업데이트하는 것이 지원되고 매우 간단합니다. hyp.is/FiP3mG6fEeqJiOfWzfKpgw/reactjs.org/docs/context.html
lustig

답변:


250

후크 사용

후크는 16.8.0에서 도입되었으므로 다음 코드에는 최소 버전 16.8.0이 필요합니다 (클래스 구성 요소 예제를 보려면 아래로 스크롤). CodeSandbox 데모

1. 동적 컨텍스트에 대한 부모 상태 설정

먼저 소비자에게 전달 될 수있는 동적 컨텍스트를 갖기 위해 부모의 상태를 사용합니다. 이것은 내가 앞으로 나아갈 진실의 단일 소스를 가지고 있음을 보장합니다. 예를 들어 부모 앱은 다음과 같습니다.

const App = () => {
  const [language, setLanguage] = useState("en");
  const value = { language, setLanguage };

  return (
    ...
  );
};

language상태에서 기억된다. 나중에 컨텍스트를 통해 language와 setter 함수 setLanguage를 모두 전달합니다 .

2. 컨텍스트 생성

다음으로 다음과 같은 언어 컨텍스트를 만들었습니다.

// set the defaults
const LanguageContext = React.createContext({
  language: "en",
  setLanguage: () => {}
});

여기에서는 language( 'en') 의 기본값 과 setLanguage컨텍스트 공급자가 소비자에게 보낼 함수를 설정합니다 . 이들은 기본값 일 뿐이며 parent에서 provider 구성 요소를 사용할 때 해당 값을 제공합니다 App.

참고 : LanguageContext후크를 사용하든 클래스 기반 구성 요소를 사용하든 동일하게 유지됩니다.

3. 컨텍스트 소비자 만들기

언어 전환기가 언어를 설정하도록하려면 컨텍스트를 통해 언어 설정 기 기능에 액세스 할 수 있어야합니다. 다음과 같이 보일 수 있습니다.

const LanguageSwitcher = () => {
  const { language, setLanguage } = useContext(LanguageContext);
  return (
    <button onClick={() => setLanguage("jp")}>
      Switch Language (Current: {language})
    </button>
  );
};

여기서는 언어를 'jp'로 설정하고 있지만 이에 대한 언어를 설정하는 자체 논리가있을 수 있습니다.

4. 공급자의 소비자 감싸기

이제 언어 전환기 구성 요소를 a에서 렌더링하고 LanguageContext.Provider컨텍스트를 통해 더 깊은 수준으로 전송해야하는 값을 전달합니다. 부모님의 App모습은 다음과 같습니다.

const App = () => {
  const [language, setLanguage] = useState("en");
  const value = { language, setLanguage };

  return (
    <LanguageContext.Provider value={value}>
      <h2>Current Language: {language}</h2>
      <p>Click button to change to jp</p>
      <div>
        {/* Can be nested */}
        <LanguageSwitcher />
      </div>
    </LanguageContext.Provider>
  );
};

이제 언어 전환기를 클릭 할 때마다 컨텍스트를 동적으로 업데이트합니다.

CodeSandbox 데모

클래스 구성 요소 사용

최신 컨텍스트 API 는 동적 컨텍스트를 갖는 훌륭한 방법을 제공하는 React 16.3에 도입되었습니다. 다음 코드에는 최소 버전 16.3.0이 필요합니다. CodeSandbox 데모

1. 동적 컨텍스트에 대한 부모 상태 설정

먼저 소비자에게 전달 될 수있는 동적 컨텍스트를 갖기 위해 부모의 상태를 사용합니다. 이것은 내가 앞으로 나아갈 진실의 단일 소스를 가지고 있음을 보장합니다. 예를 들어 부모 앱은 다음과 같습니다.

class App extends Component {
  setLanguage = language => {
    this.setState({ language });
  };

  state = {
    language: "en",
    setLanguage: this.setLanguage
  };

  ...
}

language당신이 국가들 밖에 유지할 수있는 언어 setter 메소드와 함께 상태에 저장됩니다.

2. 컨텍스트 생성

다음으로 다음과 같은 언어 컨텍스트를 만들었습니다.

// set the defaults
const LanguageContext = React.createContext({
  language: "en",
  setLanguage: () => {}
});

여기에서는 language( 'en') 의 기본값 과 setLanguage컨텍스트 공급자가 소비자에게 보낼 함수를 설정합니다 . 이들은 기본값 일 뿐이며 parent에서 provider 구성 요소를 사용할 때 해당 값을 제공합니다 App.

3. 컨텍스트 소비자 만들기

언어 전환기가 언어를 설정하도록하려면 컨텍스트를 통해 언어 설정 기 기능에 액세스 할 수 있어야합니다. 다음과 같이 보일 수 있습니다.

class LanguageSwitcher extends Component {
  render() {
    return (
      <LanguageContext.Consumer>
        {({ language, setLanguage }) => (
          <button onClick={() => setLanguage("jp")}>
            Switch Language (Current: {language})
          </button>
        )}
      </LanguageContext.Consumer>
    );
  }
}

여기서는 언어를 'jp'로 설정하고 있지만 이에 대한 언어를 설정하는 자체 논리가있을 수 있습니다.

4. 공급자의 소비자 감싸기

이제 언어 전환기 구성 요소를 a에서 렌더링하고 LanguageContext.Provider컨텍스트를 통해 더 깊은 수준으로 전송해야하는 값을 전달합니다. 부모님의 App모습은 다음과 같습니다.

class App extends Component {
  setLanguage = language => {
    this.setState({ language });
  };

  state = {
    language: "en",
    setLanguage: this.setLanguage
  };

  render() {
    return (
      <LanguageContext.Provider value={this.state}>
        <h2>Current Language: {this.state.language}</h2>
        <p>Click button to change to jp</p>
        <div>
          {/* Can be nested */}
          <LanguageSwitcher />
        </div>
      </LanguageContext.Provider>
    );
  }
}

이제 언어 전환기를 클릭 할 때마다 컨텍스트를 동적으로 업데이트합니다.

CodeSandbox 데모


컨텍스트를 초기화하는 기본값의 목적은 무엇입니까? 이러한 기본값은 항상 Provider?
ecoe

@ecoe는 정확하지만 공급자가 no를 전달 value하는 경우 소비자가 기본값을 사용합니다.
Divyanshu Maithani

1
컨텍스트가 하나의 단순한 값을 설정 / 얻도록 제한되는 이유는 무엇입니까? ... 매우 비효율적 인 것 같습니다. 더 나은 예는 기본값이 개체로있는 컨텍스트를 강조 표시하고 그에 따라 개체를 업데이트하는 것입니다.
AlxVallejo

1
setLanguage에 매개 변수가 없으면 Typescript가 내 경우에 불평합니다. setLanguage: (language: string) => {}나를 위해 작동합니다.
alex351

1
감사합니다. 이것은 내가 머리카락을 뽑고 싶지 않은 가장 명확한 방법이었습니다.
c0dezer019

49

Maithani의 위 답변은 훌륭한 솔루션이지만 후크를 사용하지 않는 클래스 구성 요소입니다. React에서 기능적 구성 요소와 후크 를 사용하는 것이 권장 되므로 useContext 및 useState 후크로 구현할 것입니다. 다음은 하위 구성 요소 내에서 컨텍스트를 업데이트하는 방법입니다.

LanguageContextMangement.js

import React, { useState } from 'react'

export const LanguageContext = React.createContext({
  language: "en",
  setLanguage: () => {}
})

export const LanguageContextProvider = (props) => {

  const setLanguage = (language) => {
    setState({...state, language: language})
  }

  const initState = {
    language: "en",
    setLanguage: setLanguage
  } 

  const [state, setState] = useState(initState)

  return (
    <LanguageContext.Provider value={state}>
      {props.children}
    </LanguageContext.Provider>
  )
}

App.js

import React, { useContext } from 'react'
import { LanguageContextProvider, LanguageContext } from './LanguageContextManagement'

function App() {

  const state = useContext(LanguageContext)

  return (
    <LanguageContextProvider>
      <button onClick={() => state.setLanguage('pk')}>
        Current Language is: {state.language}
      </button>
    </LanguageContextProvider>
  )
}

export default App

1
내 아이 컴퍼넌트 내에서이 내 설정 기능을하고있어 항상 컨텍스트를 만들 때 우리가 처음에 선언 된 하나입니다() => {}
알레한드로 Corredor

5
명확히하기 위해, 나는 당신의 예를 생각 state.setLanguage('pk')하기 때문에, 아무것도하지 않습니다 const state = useContext(LanguageContext)의 외부이다 LanguageContextProvider. 나는 제공자를 한 수준 위로 이동 한 다음 useContext한 수준 아래의 어린이에게 사용하여 문제를 해결했습니다 .
Alejandro Corredor

2
컨텍스트 공급자를 한 수준 위로 이동하지 않으려면 다음과 같이 컨텍스트 소비자를 사용할 수도 있습니다 <LanguageContext.Consumer> {value => /* access your value here */} </LanguageContext.Consumer>.
Mateen Kiani

3
LanguageContextMangement.js 파일을 구성하는 방식이 정말 마음에 듭니다. 그것은 제 생각에 일을하는 깨끗한 방법이며 지금부터 시작하겠습니다. 감사합니다!
lustig

2
감사합니다. 이런 일을 계속할 수 있도록 정말 격려가됩니다!
Mateen Kiani

3

매우 간단한 해결책 중 하나는 다음과 같이 공급자에 setState 메서드를 포함하여 컨텍스트에 상태를 설정하는 것입니다.

return ( 
            <Context.Provider value={{
              state: this.state,
              updateLanguage: (returnVal) => {
                this.setState({
                  language: returnVal
                })
              }
            }}> 
              {this.props.children} 
            </Context.Provider>
        )

소비자에서 다음과 같이 updateLanguage를 호출합니다.

// button that sets language config
<Context.Consumer>
{(context) => 
  <button onClick={context.updateLanguage({language})}> 
    Set to {language} // if you have a dynamic val for language
  </button>
<Context.Consumer>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.