CAFECA-IO / TideBit-DeFi

TideBit Decentralize Finance Version
https://tidebit-defi.vercel.app
GNU General Public License v3.0
1 stars 0 forks source link

測試 context 不同架構、context 值用不同hook包起來或不同資料型態下影響 component render 的程度 #1454

Closed arealclimber closed 9 months ago

arealclimber commented 9 months ago

在 Context 裡存有a, b兩個值,在 Trial page 有兩個 components,分別測試不同資料型態下,a 或 b 改變,會不會影響另一個 component re-render

測試內容

// pages/trial.tsx
const Trial = () => {
  return (
    <>
      <TestProvider>
        <div className="flex flex-col">
          <TestComponent1 /> <TestComponent2 />
        </div>
      </TestProvider>
    </>
  );
};
// component 各自去拿 context 值來渲染
// TestComponent1
import React, {useContext} from 'react';
import {TestContext} from '../contexts/test_context';

const TestComponent1 = ({val}: {val?: any}) => {
  const testCtx = useContext(TestContext);
  // eslint-disable-next-line no-console
  console.log('testCtx in com 1', testCtx);

  return <div>Component1: {val ? val : testCtx.a.a3.a31}</div>;
};

export default TestComponent1;
// component 各自去拿 context 值來渲染
// TestComponent2
import React, {useContext} from 'react';
import {TestContext} from '../contexts/test_context';

const TestComponent2 = ({val}: {val?: any}) => {
  const testCtx = useContext(TestContext);
  // eslint-disable-next-line no-console
  console.log('testCtx in com 2', testCtx);

  return <div>Component2: {val ? val : testCtx.b}</div>;
};

export default TestComponent2;
arealclimber commented 9 months ago

1.a, b 為 state <number>,b 改變會造成 com1, com2 渲染

test context

import React, {createContext, useEffect, useState} from 'react';
import useStateRef from 'react-usestateref';

interface ITestProvider {
  children: React.ReactNode;
}
interface ITestContext {
  a: number;
  b: number;
}

export const TestContext = createContext<ITestContext>({
  a: 0,
  b: 0,
});

export const TestProvider = ({children}: ITestProvider) => {
  const [a, setA, aRef] = useStateRef(1129);
  const [b, setB, bRef] = useStateRef(956);

  useEffect(() => {
    const int = setInterval(() => {
      const randNum = Math.floor(Math.random() * 1000);
      setB(randNum);
      // eslint-disable-next-line no-console
      console.log('value in TestContext', a, b);
    }, 3000);

    return () => {
      clearInterval(int);
    };
  }, []);

  const defaultValue = {
    a,
    b,
  };

  return <TestContext.Provider value={defaultValue}>{children}</TestContext.Provider>;
};

trial page

import React, {useContext} from 'react';
import {TestContext, TestProvider} from '../contexts/test_context';
import TestComponent1 from '../components/test_component1';
import TestComponent2 from '../components/test_component2';

const Trial = () => {
  return (
    <>
      <TestProvider>
        <div className="flex flex-col">
          <TestComponent1 /> <TestComponent2 />
        </div>
      </TestProvider>
    </>
  );
};

export default Trial;

component 1

import React, {useContext} from 'react';
import {TestContext} from '../contexts/test_context';

const TestComponent1 = ({val}: {val?: any}) => {
  const testCtx = useContext(TestContext);
  // eslint-disable-next-line no-console
  console.log('testCtx in com 1', testCtx);

  return <div>Component1: {val ? val : testCtx.a}</div>;
};

export default TestComponent1;

component 2

import React, {useContext} from 'react';
import {TestContext} from '../contexts/test_context';

const TestComponent2 = ({val}: {val?: any}) => {
  const testCtx = useContext(TestContext);
  // eslint-disable-next-line no-console
  console.log('testCtx in com 2', testCtx);

  return <div>Component2: {val ? val : testCtx.b}</div>;
};

export default TestComponent2;

2.a 為 useMemo 包起來不會改的number, b 為 useRef 每3秒隨機改變, 測試結果同 case 1

test context

import React, {createContext, useEffect, useMemo, useState} from 'react';
import useStateRef from 'react-usestateref';

interface ITestProvider {
  children: React.ReactNode;
}
interface ITestContext {
  a: number;
  b: number;
}

export const TestContext = createContext<ITestContext>({
  a: 0,
  b: 0,
});

export const TestProvider = ({children}: ITestProvider) => {
  // const [a, setA, aRef] = useStateRef(1129);
  const [b, setB, bRef] = useStateRef(956);

  const a = useMemo(() => {
    return Math.floor(Math.random() * 1000);
  }, []);

  useEffect(() => {
    const int = setInterval(() => {
      const randNum = Math.floor(Math.random() * 1000);
      setB(randNum);
      // eslint-disable-next-line no-console
      console.log('setInterval in TestContext', a, b);
    }, 3000);

    return () => {
      clearInterval(int);
    };
  }, []);

  const defaultValue = {
    // a: aRef.current,
    a,
    b: bRef.current,
  };

  return <TestContext.Provider value={defaultValue}>{children}</TestContext.Provider>;
};

3.a為 nested object ,b 為 useRef,a31 改變,測試結果跟case 1 相同

test context

import React, {createContext, useEffect, useMemo, useState} from 'react';
import useStateRef from 'react-usestateref';

interface IA {
  a1: string;
  a2: number;
  a3: {
    a31: string;
    a32: boolean;
  };
}

interface ITestProvider {
  children: React.ReactNode;
}
interface ITestContext {
  a: IA;
  b: number;
}

export const TestContext = createContext<ITestContext>({
  a: {
    a1: '',
    a2: 0,
    a3: {
      a31: '',
      a32: false,
    },
  },
  b: 0,
});

export const TestProvider = ({children}: ITestProvider) => {
  const [a, setA, aRef] = useStateRef({
    a1: 'a1',
    a2: 1,
    a3: {
      a31: 'a31',
      a32: true,
    },
  });

  const [b, setB, bRef] = useStateRef(956);

  useEffect(() => {
    const int = setInterval(() => {
      // change a31 randomly
      setA(prev => {
        return {
          ...prev,
          a3: {
            ...prev.a3,
            a31: Math.random().toString(),
          },
        };
      });
    }, 3000);

    return () => {
      clearInterval(int);
    };
  }, []);

  const defaultValue = {
    a: aRef.current,
    b: bRef.current,
  };

  return <TestContext.Provider value={defaultValue}>{children}</TestContext.Provider>;
};
arealclimber commented 9 months ago

taking 3 hrs