React에서 컨텍스트는 컴포넌트의 각 레이어에 대한 props를 수동으로 추가하지 않고 컴포넌트 트리 간에 데이터를 전달하는 방법입니다. 컨텍스트는 컴포넌트를 통해 명시적으로 props 레이어를 전달하지 않고도 컴포넌트 간에 지정된 값을 공유하는 방법을 제공합니다. 나무에.
이 튜토리얼의 운영 환경: Windows 10 시스템, 반응 버전 17.0.1, Dell G3 컴퓨터.
컨텍스트는 구성 요소의 각 레이어에 소품을 수동으로 추가하지 않고도 구성 요소 트리 간에 데이터를 전달하는 방법을 제공합니다. 일반적인 React 애플리케이션에서 데이터는 props를 통해 위에서 아래로(상위에서 하위로) 전달되지만 이 접근 방식은 특정 유형의 속성(예: 로케일 기본 설정, UI 테마)에 대해 매우 번거롭습니다. 응용 프로그램. 컨텍스트는 컴포넌트 트리의 각 레벨을 통해 props를 명시적으로 전달하지 않고도 컴포넌트 간에 이러한 값을 공유할 수 있는 방법을 제공합니다.
컨텍스트는 현재 인증된 사용자, 테마 또는 기본 언어와 같은 구성 요소 트리에 "전역"인 데이터를 공유하도록 설계되었습니다. 예를 들어, 다음 코드에서는 "theme" 속성을 통해 버튼 구성 요소의 스타일을 수동으로 조정합니다.
class App extends React.Component { render() { return <Toolbar theme="dark" /> }}function Toolbar(props) { // Toolbar 구성요소는 추가 "테마" 속성을 허용하며 이 속성은 ThemeButton에 전달됩니다. 요소. // 애플리케이션의 모든 단일 버튼이 테마의 값을 알아야 한다면 문제가 될 것입니다. // 이 값은 모든 구성 요소에 전달되어야 하기 때문입니다. return ( <p> <ThemedButton theme={props.theme} /> </p> );}class ThemedButton은 React.Component를 확장합니다. { render() { return <Button theme={this.props.theme} /> } }// 소품 통과: 앱 -> 도구 모음 -> ThemedButton// 중첩이 너무 깊으면 소품을 레이어별로 전달해야 합니다. 중간에 소품이 필요하지 않더라도 매우 번거로워 보입니다.컨텍스트를 사용하면 소품이 중간 요소를 통해 전달되는 것을 피할 수 있습니다.
// 컨텍스트를 사용하면 각 구성 요소를 통해 명시적으로 값을 전달할 필요 없이 구성 요소 트리에 값을 전달할 수 있습니다. // 현재 테마에 대한 컨텍스트를 생성합니다(기본값은 "light"입니다). const ThemeContext = React.createContext('light');class App Extensions React.Component { render() { // Provider를 사용하여 현재 테마를 다음 구성 요소 트리에 전달합니다. // 아무리 깊어도 모든 구성요소는 이 값을 읽을 수 있습니다. // 이 예에서는 "dark"를 현재 값으로 전달합니다. return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ) }}// 중간 구성 요소는 더 이상 전달할 테마를 지정할 필요가 없습니다. function Toolbar() { return ( <p> <ThemedButton /> </p> );}class ThemedButton extends React.Component { // 현재 테마 컨텍스트를 읽으려면 contextType을 지정하세요. // React는 가장 가까운 테마 제공자를 찾아 그 값을 사용합니다. // 이 예에서 현재 테마 값은 "dark"입니다. static contextType = ThemeContext; render() { return <Button theme={this.context} /> }}// ThemeButto.contextType = ThemeContext를 사용할 수도 있습니다.컨텍스트 개체를 만듭니다. React가 이 Context 객체를 구독하는 구성 요소를 렌더링할 때 구성 요소는 구성 요소 트리에서 자신과 가장 가까운 일치하는 Provider로부터 현재 컨텍스트 값을 읽습니다.
구성 요소가 있는 트리에 일치하는 공급자가 없는 경우에만 해당 defaultValue 매개 변수가 적용됩니다. 이는 구성 요소를 래핑하기 위해 공급자를 사용하지 않고 구성 요소를 테스트하는 데 도움이 됩니다. 참고: undef가 Provider 값에 전달되면 소비 구성 요소의 defaultValue가 적용되지 않습니다.
각 Context 객체는 구성 요소를 사용하여 컨텍스트 변경 사항을 구독할 수 있는 Provider React 구성 요소를 반환합니다.
공급자는 값 특성을 받아 소비 구성 요소에 전달합니다. 공급자는 여러 소비자 구성 요소와 해당 관계를 가질 수 있습니다. 여러 공급자를 중첩하여 사용할 수도 있으며 내부 레이어가 외부 레이어의 데이터를 덮어씁니다.
Provider의 값이 변경되면 그 안의 모든 소비 구성 요소가 다시 렌더링됩니다. Provider와 내부 소비자 구성 요소 모두 shouldComponentUpdate 함수의 적용을 받지 않으므로 상위 구성 요소가 업데이트를 종료하더라도 소비자 구성 요소를 업데이트할 수 있습니다.
클래스에 마운트된 contextType 속성은 React.createContext()에 의해 생성된 Context 객체에 다시 할당됩니다. 이를 통해 this.context를 사용하여 가장 최근 컨텍스트의 값을 사용할 수 있습니다. 렌더링 기능을 포함하여 모든 라이프사이클에서 액세스할 수 있습니다.
import MyContext from './MyContext';class MyClass extends React.Component { componentDidMount() { let value = this.context; /* 컴포넌트가 마운트된 후 MyContext 컴포넌트의 값을 사용하여 일부 부작용 작업을 수행합니다* / } componentDidUpdate() { let value = this.context; /* ... */ } componentWillUnmount() { let value = this.context /* ... */ } render() { let value = this.context; ; /* MyContext 구성 요소의 값을 기반으로 렌더링합니다.*/ } // 또는 위의 예와 같이 static contextType = MyContext;}MyClass.contextType = MyContext를 사용합니다.여기에서 React 구성 요소는 컨텍스트 변경 사항을 구독할 수도 있습니다. 이를 통해 기능 구성 요소의 컨텍스트를 구독할 수 있습니다.
이를 위해서는 어린이로서의 기능이 필요합니다. 이 함수는 현재 컨텍스트 값을 수신하고 React 노드를 반환합니다. 함수에 전달된 값은 구성 요소 트리에서 이 컨텍스트에 가장 가까운 공급자가 제공한 값과 동일합니다. 해당 제공자가 없는 경우 value 매개변수는 createContext()에 전달된 defaultValue와 동일합니다.
컨텍스트 개체는 문자열 유형인 displayName이라는 속성을 허용합니다. React DevTools는 이 문자열을 사용하여 표시할 컨텍스트를 결정합니다.
다음 구성요소는 DevTools에서 MyDisplayName으로 표시됩니다.
const MyContext = React.createContext(/* 일부 값 */);MyContext.displayName = 'MyDisplayName';<MyContext.Provider> // DevTools의 "MyDisplayName.Provider" <MyContext.Consumer> // "MyDisplayName.Consumer" In 개발자 도구위의 테마 예에서는 동적 값을 사용하여 더 복잡한 사용법을 달성할 수 있습니다.
테마-context.js
import const theme = { light: { foreground: '#000000', background: '#eeeeee', }, dark: { foreground: '#ffffff', background: '#222222', },};export const ThemeContext = React .createContext(themes.dark); // 기본값입니다.테마-button.js
import { ThemeContext } from './theme-context'; class ThemedButton extends React.Component { render() { let props = this.props; // ThemeContext에서 기본값 가져오기 let theme = this.context return ( < 버튼 {...props} style={{BackgroundColor: theme.Background}} /> ) } // static contextType = ThemeContext;}ThemedButton.contextType = ThemeContext;export default ThemeButton;app.js
import { ThemeContext, themes } from './theme-context';import ThemedButton from './themed-button';// ThemedButton을 사용한 중간 구성요소 함수 Toolbar(props) { return ( <ThemedButton onClick={props.changeTheme } > 테마 변경 </ThemedButton> );} class App extends React.Component { constructor(props) { super(props); this.state = { theme: themes.light, }; .setState(state => ({ theme: state.theme === themes.dark ? theme.light : themes.dark, })) } render() { // ThemeProvider 내부의 ThemeButton 버튼 구성 요소에서 사용됩니다. 상태 값, // 및 외부 구성 요소는 기본 테마 값을 사용합니다. return ( <Page> <ThemeContext.Provider value={this.state.theme}> <ToolbarchangeTheme={this.toggleTheme} /> </ThemeContext .Provider> <Section> <ThemedButton /> </Section> </Page> ) }}ReactDOM.render(<App />, document.root);// ThemeContext.Provider에 의해 래핑된 구성 요소는 ThemeContext를 사용할 수 있습니다. 툴바의 값// ThemedButton은 this.context를 사용하여 값을 얻을 수 있습니다. 상태를 업데이트하는 방법은 props를 통해 전달하는 것이며 업데이트는 하위 구성 요소에 의해 트리거됩니다. 컨텍스트를 통한 방법은 아래에서 설명합니다.위의 예에서는 앱의 테마 값을 변경하기 위해 props를 통해 업데이트 함수를 전달합니다. 우리는 구성 요소 트리에 깊게 중첩된 구성 요소에서 컨텍스트를 업데이트해야 한다는 것을 알고 있습니다. 이 시나리오에서는 컨텍스트를 통해 함수를 전달하여 소비자 구성 요소가 컨텍스트를 업데이트하도록 할 수 있습니다.
테마-context.js
// createContext에 전달된 기본 값 데이터 구조가 호출 구성요소(소비자)와 일치하는지 확인하세요! import const ThemeContext = React.createContext({ theme: themes.dark,ggleTheme: () => {}, // 테마를 업데이트하는 메서드를 정의하고 전달합니다.});테마 토글러-button.js
import { ThemeContext } from './theme-context';function ThemeTogglerButton() { // 테마 토글러 버튼은 테마 값을 가져올 뿐만 아니라 컨텍스트(아래 app.js 부분)에서 전환Theme 함수도 가져옵니다. return ( < ThemeContext.Consumer> {({theme,ggleTheme}) => ( <button onClick={toggleTheme} style={{BackgroundColor: theme.Background}}> 테마 전환 </button> )} </ThemeContext.Consumer> ); }기본 ThemeTogglerButton 내보내기;app.js
import { ThemeContext, themes } from './theme-context';import ThemeTogglerButton from './theme-toggler-button';class 앱 확장 React.Component { constructor(props) { super(props) = ( ) => { this.setState(state => ({ theme: state.theme === themes.dark ? theme.light : themes.dark, }))); // State에는 업데이트 함수도 포함되어 있습니다. 컨텍스트 제공자에게 전달됩니다. this.state = { theme: themes.light,ggleTheme: this.toggleTheme, // 업데이트 함수를 정의하고 컨텍스트를 통해 전달합니다. } } render() { // 전체 상태가 공급자에 전달됩니다. return ( < ThemeContext.Provider value={this.state}> <Content /> </ThemeContext.Provider> ) }}function Content() { return ( <p> <ThemeTogglerButton /> </p> );}ReactDOM.render( <App />, document.root);컨텍스트가 신속하게 다시 렌더링되도록 하기 위해 React는 각 소비자 구성 요소의 컨텍스트를 구성 요소 트리의 별도 노드로 만들어야 합니다.
// 테마 컨텍스트, 기본 테마는 "light" 값입니다. const ThemeContext = React.createContext('light'); // 사용자 로그인 컨텍스트 const UserContext = React.createContext({ name: 'Guest',}); React .Component { render() { const { signedInUser, theme } = this.props; // 초기 컨텍스트 값을 제공하는 앱 컴포넌트 return ( <ThemeContext.Provider value={theme}> <UserContext.Provider value={signedInUser} > < Layout /> </UserContext.Provider> </ThemeContext.Provider> ); }}function Layout() { return ( <p> <Sidebar /> <Content /> </p> );}// 구성 요소 여러 컨텍스트 함수를 사용할 수 있음 Content() { return ( <ThemeContext.Consumer> {theme => ( <UserContext.Consumer> {user => ( <ProfilePage user={user} theme={theme} /> )} </UserContext . 소비자> )} </ThemeContext.Consumer> );}두 개 이상의 컨텍스트 값이 자주 함께 사용되는 경우 이러한 값을 제공하기 위해 자체 렌더링 구성 요소를 만드는 것을 고려할 수 있습니다.
컨텍스트는 참조 ID를 사용하여 렌더링 시기를 결정하기 때문에 공급자의 상위 구성 요소가 다시 렌더링될 때 소비자 구성 요소에서 예기치 않은 렌더링을 트리거할 수 있는 몇 가지 함정이 있을 수 있습니다. 예를 들어, 공급자가 다시 렌더링될 때마다 다음 코드는 다음 소비자 구성 요소를 모두 다시 렌더링합니다. 왜냐하면 value 속성은 항상 새 개체에 할당되기 때문입니다.
클래스 앱 확장 React.Component { render() { return ( <MyContext.Provider value={{something: 'something'}}> <Toolbar /> </MyContext.Provider> }}이러한 상황을 방지하기 위해 값 상태가 상위 노드의 상태로 승격됩니다.
class App extends React.Component { constructor(props) { super(props); // 여러 번 렌더링한 후에도 상태는 유지됩니다. 값이 변경되지 않으면 다음 소비자 구성 요소는 다시 렌더링되지 않습니다. this.state = { value: { 무엇인가: 'something'}, }; } render() { return ( <Provider value={this.state.value}> <Toolbar /> </Provider> );