Skip to content

Commit

Permalink
Merge pull request #1 from jeonghwan-kim/feat/myreact-context
Browse files Browse the repository at this point in the history
MyReact 컨택스트 개선
  • Loading branch information
jeonghwan-kim committed Apr 14, 2024
2 parents 7261cec + 079fff7 commit 0b96a35
Show file tree
Hide file tree
Showing 5 changed files with 7,751 additions and 1,851 deletions.
12 changes: 12 additions & 0 deletions 2-hook/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// package.json에서 꺼냄. babel-jest rootMode 설정 동작때문.
module.exports = {
presets: [
"@babel/preset-env",
[
"@babel/preset-react",
{
runtime: "automatic",
},
],
],
};
23 changes: 16 additions & 7 deletions 2-hook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,38 @@
"description": "",
"main": "src/main.js",
"scripts": {
"start": "webpack serve --config ../shared/webpack.config.js"
"start": "webpack serve --config ../shared/webpack.config.js",
"test": "jest"
},
"author": "Jeonghwan Kim <ej88ej@gmail.com>",
"license": "ISC",
"dependencies": {
"@babel/core": "^7.17.10",
"@babel/preset-env": "^7.24.3",
"@babel/preset-react": "^7.16.7",
"@testing-library/react": "^14.2.2",
"babel-jest": "^29.7.0",
"babel-loader": "^8.2.5",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-environment-node": "^29.7.0",
"msw": "^1.2.1",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-test-renderer": "^18.2.0",
"webpack": "^5.72.1",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.9.0"
},
"babel": {
"presets": [
[
"@babel/preset-react",
"jest": {
"testEnvironment": "jsdom",
"transform": {
"\\.jsx?$": [
"babel-jest",
{
"runtime": "automatic"
"rootMode": "upward"
}
]
]
}
}
}
31 changes: 25 additions & 6 deletions 2-hook/src/lib/MyReact.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,30 +81,49 @@ const MyReact = (function MyReact() {
cleanups.forEach((cleanup) => typeof cleanup === "function" && cleanup());
}

function createContext(initialValue) {
const emitter = createEventEmitter(initialValue);
function createContext(defaultValue) {
let emitter;

function Provider({ value, children }) {
if (!emitter) {
emitter = createEventEmitter(value);
}

React.useEffect(() => {
emitter.set(value);
}, [value]);

return <>{children}</>;
}

function getValue() {
return emitter ? emitter.get() : defaultValue;
}

function on(handler) {
emitter?.on(handler);
}

function off(handler) {
emitter?.off(handler);
}

return {
Provider,
emitter,
getValue,
on,
off,
};
}

function useContext(context) {
const [value, setValue] = React.useState(context.emitter.get());
const [value, setValue] = React.useState(context.getValue());

React.useEffect(() => {
context.emitter.on(setValue);
context.on(setValue);

return () => {
context.emitter.off(setValue);
context.off(setValue);
};
}, [context]);

Expand Down
33 changes: 33 additions & 0 deletions 2-hook/test/MyReact.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { render } from "@testing-library/react";

import MyReact from "../src/lib/MyReact";

let consumerRenderCount = 0;

describe("useContext", () => {
test("컴포넌트가 한 번만 렌더 된다.", () => {
// 컨택스트를 만든다.
const context = MyReact.createContext({ foo: 0 });

// 컨택스트에 값을 제공한다.
const Provider = ({ children }) => {
return <context.Provider value={{ foo: 1 }}>{children}</context.Provider>;
};

// 훅으로 컨택스트 값을 사용한다.
const Consumer = () => {
consumerRenderCount = consumerRenderCount + 1;
const value = MyReact.useContext(context);
return <div>{value.foo}</div>;
};

const { getByText } = render(
<Provider>
<Consumer />
</Provider>
);

expect(getByText(1)).toBeTruthy();
expect(consumerRenderCount).toBe(1);
});
});

0 comments on commit 0b96a35

Please sign in to comment.