아카이브

[Solid] Syntax | 11. Context 본문

Frontend/SolidJS

[Solid] Syntax | 11. Context

Rayi 2024. 6. 27. 14:06

한 컴포넌트에서 다른 컴포넌트로 데이터를 전달할 때 props를 사용합니다.

 

하지만 props는 자신 바로 위 컴포넌트의 값만 전달 받을 수 있다는 제약이 있어,

 

한 단계 더 위의 컴포넌트로부터 값을 받으려면 중간 컴포넌트가 props을 전달해주어야 합니다.

 

이때문에 컴포넌트 계층이 길어질수록 중간 컴포넌트들은 자신은 사용하지도 않는 props를 받아야 하는 문제가 있습니다.

Component B는 props를 사용할 일이 없지만, Component C가 props를 사용할 수 있도록 props를 전달해주어야 합니다.

Context API를 사용한다면, props의 명시 없이도 자손 컴포넌트들에게 props를 전달해줄 수 있습니다.

 

Context API에는 크게 두 가지 함수가 있습니다.

 

  1. createContext( ) : context 객체를 생성하여 반환합니다.
  2. useContext(context) : context 객체를 사용하여 provider 컴포넌트를 통해 전달하는 props 값을 반환합니다.
import { createContext, useContext } from "solid-js";

const CounterContext = createContext();

const contextProp = useContext(CounterContext);

provider는 context 객체에 기본적으로 포함되어 있는 하위 컴포넌트입니다.

 

provider 태그 안에 속하는 요소들은 provider를 통해 전달하는 props 값을 useContext( )를 이용해 전달 받을 수 있습니다.

import { createContext, useContext } from "solid-js";

const Context = createContext();

// Comp1에서 선언한 value를 사용합니다.
function Comp3() {
	const value = useContext(Context);  // useContext로 provider의 value값을 가져옵니다.
    
    return (
    	<p>{value}</p>
    );
}

// value를 사용하는 Comp3의 부포 컴포넌트이지만, value를 prop으로 받지 않습니다.
function Comp2() {
	return (
    	<Comp3/>
    );
}

function Comp1() {
	const name = "javascript";
    
    return (
        <Context.Provider value={name}>
            // 이 안의 컴포넌트들은 value prop을 prop으로 받지 않아도
            // useContext()를 이용해 받을 수 있습니다.
            <Comp2/>
        </Context.Provider>
    );
}

provider에서 두 개 이상의 값도 전달할 수 있습니다. 이 때는 중괄호{ }로 값들을 묶어주면 됩니다.

import { createSignal, createContext, useContext } from "solid-js";

const CounterContext = createContext();

function IncrementButton() {
  const { setCount } = useContext(CounterContext);
  return <button onClick={() => setCount(c => c + 1)}>Increment</button>;
}

function DisplayCount() {
  const { count } = useContext(CounterContext);
  return <div>Count: {count()}</div>;
}

function App() {
  const [count, setCount] = createSignal(0);
  // 두 개 이상의 value
  return (
    <CounterContext.Provider value={{ count, setCount }}>
      <DisplayCount />
      <IncrementButton />
    </CounterContext.Provider>
  );
}

 

아래 예시는 main.js - counter.js 두 개 컴포넌트가 nested 된 구조에서 context를 사용하는 코드입니다.

 

counter.js는 컴포넌트가 아닌 context의 wrapper 컴포넌트를 제공하는 코드입니다.

// main.js
import { render } from "solid-js/web";
import Nested from "./nested";
import { CounterProvider } from "./counter";

function App() {
  return <>
    <h1>Welcome to Counter App</h1>
    <Nested />
  </>
};

render(() => (
  <CounterProvider count={1}>
    <App />
  </CounterProvider>
), document.getElementById("app"));
// nested.js
import { useCounter } from "./counter";

export default function Nested() {
  const [count, { increment, decrement }] = useCounter();
  return (
    <>
      <div>{count()}</div>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </>
  );
};
// counter.js
import { createSignal, createContext, useContext } from "solid-js";

const CounterContext = createContext();

export function CounterProvider(props) {
  const [count, setCount] = createSignal(props.count || 0),
    counter = [
      count,
      {
        increment() {
          setCount(c => c + 1);
        },
        decrement() {
          setCount(c => c - 1);
        }
      }
    ];

  return (
    <CounterContext.Provider value={counter}>
      {props.children}
    </CounterContext.Provider>
  );
}

export function useCounter() { return useContext(CounterContext); }

 

728x90
Comments