렌더링 기능 외부에서 React Context에 액세스


93

Redux 대신 새로운 React Context API를 사용하여 새로운 앱을 개발 Redux중입니다. 예를 들어 사용자 목록 을 가져와야 할 때를 사용하여 단순히 componentDidMount내 작업을 호출 했지만 이제는 React Context를 사용하여 내 작업이 내부에 있습니다. 내 렌더링 함수 안에있는 내 소비자, 즉 내 렌더링 함수가 호출 될 때마다 내 사용자 목록을 가져 오기 위해 내 작업을 호출하고 불필요한 요청을 많이 할 것이기 때문에 좋지 않습니다.

그렇다면 componentDidMount렌더링을 호출하는 대신 in과 같이 내 작업을 한 번만 호출 할 수있는 방법은 무엇입니까?

예를 들어 다음 코드를 살펴보십시오.

다음 Providers과 같이 하나의 구성 요소로 모든 것을 래핑한다고 가정 해 보겠습니다 .

import React from 'react';

import UserProvider from './UserProvider';
import PostProvider from './PostProvider';

export default class Provider extends React.Component {
  render(){
    return(
      <UserProvider>
        <PostProvider>
          {this.props.children}
        </PostProvider>
      </UserProvider>
    )
  }
}

그런 다음이 Provider 구성 요소를 다음과 같이 모든 앱을 래핑합니다.

import React from 'react';
import Provider from './providers/Provider';
import { Router } from './Router';

export default class App extends React.Component {
  render() {
    const Component = Router();
    return(
      <Provider>
        <Component />
      </Provider>
    )
  }
}

예를 들어 내 사용자보기에서 다음과 같이 표시됩니다.

import React from 'react';
import UserContext from '../contexts/UserContext';

export default class Users extends React.Component {
  render(){
    return(
      <UserContext.Consumer>
        {({getUsers, users}) => {
          getUsers();
          return(
            <h1>Users</h1>
            <ul>
              {users.map(user) => (
                <li>{user.name}</li>
              )}
            </ul>
          )
        }}
      </UserContext.Consumer>
    )
  }
}

내가 원하는 것은 다음과 같습니다.

import React from 'react';
import UserContext from '../contexts/UserContext';

export default class Users extends React.Component {
  componentDidMount(){
    this.props.getUsers();
  }

  render(){
    return(
      <UserContext.Consumer>
        {({users}) => {
          getUsers();
          return(
            <h1>Users</h1>
            <ul>
              {users.map(user) => (
                <li>{user.name}</li>
              )}
            </ul>
          )
        }}
      </UserContext.Consumer>
    )
  }
}

그러나 물론 위의 예 getUsers는 내 사용자 뷰 소품에 살지 않기 때문에 작동 하지 않습니다. 이것이 가능하다면 올바른 방법은 무엇입니까?

답변:


144

편집 : 의 반응 - 후크의 도입으로 v16.8.0 , 당신은을 사용하여 기능적 구성 요소의 컨텍스트를 사용할 수있는 useContext후크를

const Users = () => {
    const contextValue = useContext(UserContext);
    // rest logic here
}

편집 : 버전 16.6.0 부터. 당신은 사용 수명주기 방법에 컨텍스트를 사용할 수있다 this.context처럼

class Users extends React.Component {
  componentDidMount() {
    let value = this.context;
    /* perform a side-effect at mount using the value of UserContext */
  }
  componentDidUpdate() {
    let value = this.context;
    /* ... */
  }
  componentWillUnmount() {
    let value = this.context;
    /* ... */
  }
  render() {
    let value = this.context;
    /* render something based on the value of UserContext */
  }
}
Users.contextType = UserContext; // This part is important to access context values

버전 16.6.0 이전에는 다음과 같은 방식으로 수행 할 수 있습니다.

라이프 사이클 방법에서 Context를 사용하려면 다음과 같이 구성 요소를 작성하십시오.

class Users extends React.Component {
  componentDidMount(){
    this.props.getUsers();
  }

  render(){
    const { users } = this.props;
    return(

            <h1>Users</h1>
            <ul>
              {users.map(user) => (
                <li>{user.name}</li>
              )}
            </ul>
    )
  }
}
export default props => ( <UserContext.Consumer>
        {({users, getUsers}) => {
           return <Users {...props} users={users} getUsers={getUsers} />
        }}
      </UserContext.Consumer>
)

일반적으로 앱에서 하나의 컨텍스트를 유지하고 위의 로그인을 HOC로 패키징하여 재사용하는 것이 좋습니다. 다음과 같이 쓸 수 있습니다.

import UserContext from 'path/to/UserContext';

const withUserContext = Component => {
  return props => {
    return (
      <UserContext.Consumer>
        {({users, getUsers}) => {
          return <Component {...props} users={users} getUsers={getUsers} />;
        }}
      </UserContext.Consumer>
    );
  };
};

그런 다음 다음과 같이 사용할 수 있습니다.

export default withUserContext(User);

그것이 그것을하는 방법입니다! 그러나 나는 내 구성 요소를 다른 것들로 래핑하고 있으므로 이러한 방식으로 코드가 점점 더 복잡해질 것입니다. 따라서 컨텍스트가있는 라이브러리와 데코레이터를 사용하면 코드가 훨씬 더 간단 해집니다. 하지만 답을 주셔서 감사합니다!
Gustavo Mendonça

그것은 나를 위해 일을 나던, 내가 가진 컨텍스트 GitHub의 사용
PassionateDeveloper

1
Shubham Khatri의 대답은 정확합니다. 작은 오타로 인해 실행을 막을 수 있습니다. 중괄호는 암시 적 반환을 방지합니다. 괄호로 바꾸십시오.
VDubs

1
this.context동일한 구성 요소 내에서 여러 컨텍스트 를 사용하는 방법을 설명 할 수 있습니까 ? UserContext 및 PostContext에 액세스해야하는 구성 요소가 있다고 가정 해 보겠습니다. 어떻게 처리 할 수 ​​있습니까? 내가 볼 수있는 것은 둘 다 혼합 된 컨텍스트를 만드는 것이지만 이것이 유일한 해결책이거나 더 나은 해결책일까요?
Gustavo Mendonça

1
@ GustavoMendonça this.context API 구현을 사용하여 단일 컨텍스트 만 구독 할 수 있습니다. 당신이 더 많은 것보다는 읽을 필요가있는 경우에는 렌더링 소품 패턴을 따를 필요
하기 Shubham 카트리

3

좋아, 나는 이것을 제한하는 방법을 찾았다. with-context라이브러리를 사용하여 모든 소비자 데이터를 구성 요소 소품에 삽입 할 수있었습니다.

그러나 동일한 구성 요소에 둘 이상의 소비자를 삽입하려면이 라이브러리를 사용하여 혼합 소비자를 만들어야하므로 코드가 우아하지 않고 비생산적입니다.

이 라이브러리에 대한 링크 : https://github.com/SunHuawei/with-context

편집 : 실제로 with-context제공 하는 다중 컨텍스트 API를 사용할 필요가 없습니다. 실제로 간단한 API를 사용하고 각 컨텍스트에 대한 데코레이터를 만들 수 있으며 구성 요소에서 둘 이상의 소비자를 사용하려면 원하는만큼 데코레이터를 클래스 위에 선언하세요!


1

제 부분 .bind(this)에서는 이벤트 에 추가하는 것으로 충분했습니다 . 이것이 내 구성 요소의 모습입니다.

// Stores File
class RootStore {
   //...States, etc
}
const myRootContext = React.createContext(new RootStore())
export default myRootContext;


// In Component
class MyComp extends Component {
  static contextType = myRootContext;

  doSomething() {
   console.log()
  }

  render() {
    return <button onClick={this.doSomething.bind(this)}></button>
  }
}

1
이 코드는 훨씬 간단 해 보이지만 실제로 값에 액세스하거나 RootStore 인스턴스와 전혀 상호 작용하지 않습니다. 두 개의 파일로 분할 된 예제와 반응 형 UI 업데이트를 보여줄 수 있습니까?
dcsan 2019

-8

자식의 소품으로 액세스하려면 상위 부모 구성 요소에 컨텍스트를 전달해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.