React上下文不会更新(Typescript)

huangapple go评论82阅读模式
英文:

React context will not update (Typescript)

问题

以下是您提供的代码的翻译:

已经卡在这里一周了找不到任何有效的解决方法
这是我的上下文文件

import { createContext, useState, useEffect } from 'react';
import * as sm from './StatManagement';
import { PlayerMenu, BossHpBar, BossArea, MainPage } from './MainPage';
// 用于 Boss 血条

接口 BossContextValue {
  BossHP: 数字;
  setBossHP: (value: number) => void;  // 接受数字的函数
}

出口 const BossContext = createContext<BossContextValue>({
  BossHP: sm.boss_stats.hp,
  setBossHP: () => { },
});

函数 ContextManagement() {

  const [BossHP, setBossHP] = useState(sm.boss_stats.hp);
  useEffect(() => {
    // 这个永远不会触发
    console.log('BossHP 更新:', BossHP);
  }, [BossHP]);
  返回 (
    <BossContext.Provider value={{ BossHP, setBossHP }}>
      <PlayerMenu player='' isPlayerTurn={false} />
      <BossHpBar />
    </BossContext.Provider>
  )
}

默认出口 ContextManagement;

我试图做的是创建一个全局状态来存储 BossHP当点击此按钮时它应该更新

出口 const PlayerMenu: React.FC<PlayerMenuProps> = ({ player, isPlayerTurn }) => {
  const { setBossHP } = useContext(BossContext);
  // 其他元素

  <div className='grid grid-cols-2 grid-rows-2'>
    {current_attacks.map(
      (attack, index) =>
        <li key={index} className='atk-btn'>
          <button onClick={() => {
            const new_hp = pa.PlayerAttack(attack);

            setIsAttackAreaShown(true);
            setCurrentAttack(attack);

            setBossHP(new_hp);
          }}>
            // 无关的内容
          }
        </li>
    )}
  </div>
}

然后它 *应该* 在这里更新进度条这个组件只通过上下文与 PlayerMenu 相关联

出口 const BossHpBar = () => {
  const { BossHP } = useContext(BossContext);
  useEffect(() => {
    // 不会更新
    console.log('BossHP 更新:', BossHP);
  }, [BossHP]);

  console.log("boss 血条已渲染" + BossHP)
  返回 (
    <progress className={
      'block h-8 glow-ani-border-black boss-prog w-10/12'
    } value={BossHP} max={sm.boss_stats.max_hp}></progress>
  )
}

请注意,这只是您提供的代码的翻译,没有附加内容。如果您需要任何其他帮助,请告诉我。

英文:

Been stuck here for a week and can't find anything that works.
Here is my context file:

import { createContext, useState, useEffect } from &#39;react&#39;;
import * as sm from &#39;./StatManagement&#39;;
import { PlayerMenu, BossHpBar, BossArea, MainPage } from &#39;./MainPage&#39;;
//used for the boss hp bar
interface BossContextValue {
BossHP: number;
setBossHP: (value: number) =&gt; void;  // Function that takes a number
}
export const BossContext = createContext&lt;BossContextValue&gt;({
BossHP: sm.boss_stats.hp,
setBossHP: () =&gt; { },
});
function ContextManagement() {
const [BossHP, setBossHP] = useState(sm.boss_stats.hp);
useEffect(() =&gt; {
//This never triggers 
console.log(&#39;BossHP updated:&#39;, BossHP);
}, [BossHP]);
return (
&lt;BossContext.Provider value={{ BossHP, setBossHP }}&gt;
&lt;PlayerMenu player=&#39;&#39; isPlayerTurn={false} /&gt;
&lt;BossHpBar /&gt;
&lt;/BossContext.Provider&gt;
)
}
export default ContextManagement;

What I'm trying to do is create a global state for BossHP. It should update when this button is clicked:

 export const PlayerMenu: React.FC&lt;PlayerMenuProps&gt; = ({ player, isPlayerTurn }) =&gt; {
const { setBossHP } = useContext(BossContext);
//other elements
&lt;div className=&#39; grid grid-cols-2 grid-rows-2&#39;&gt;
{current_attacks.map(
(attack, index) =&gt;
&lt;li key={index} className=&#39;atk-btn&#39;&gt;
&lt;button onClick={() =&gt; {
const new_hp = pa.PlayerAttack(attack);
setIsAttackAreaShown(true);
setCurrentAttack(attack);
setBossHP(new_hp);
}}&gt;
//unrelated
}

Then it should update the progress bar here. This component is only linked to PlayerMenu through the context.

 export const BossHpBar = () =&gt; {
const { BossHP } = useContext(BossContext);
useEffect(() =&gt; {
//doesn&#39;t update
console.log(&#39;BossHP updated:&#39;, BossHP);
}, [BossHP]);
console.log(&quot;boss hp bar rendered&quot; + BossHP)
return (
&lt;progress className={
&#39;block h-8 glow-ani-border-black boss-prog w-10/12&#39;
} value={BossHP} max={sm.boss_stats.max_hp}&gt;&lt;/progress&gt;
)
}

答案1

得分: 1

I created a simple working example based on your code, so when you click the button - the variable in the progress bar is updating.
You can check an example in playground here

import React, { createContext, useState, useContext, useEffect } from 'react';

const sm = {
  boss_stats: {
    hp: 100,
    max_hp: 200,
  },
};

interface PlayerMenuProps {
  player: string;
  isPlayerTurn: boolean;
}

export const BossContext = createContext<{
  BossHP: number;
  setBossHP: (value: number) => void;
}>({
  BossHP: sm.boss_stats.hp,
  setBossHP: () => {},
});

const PlayerMenu: React.FC<PlayerMenuProps> = ({ player, isPlayerTurn }) => {
  const { setBossHP } = useContext(BossContext);

  const handleAttack = () => {
    const new_hp = Math.max(0, Math.floor(Math.random() * 100));
    setBossHP(new_hp);
  };

  return (
    <div>
      <button onClick={handleAttack}>Attack</button>
    </div>
  );
};

const BossHpBar = () => {
  const { BossHP } = useContext(BossContext);

  return (
    <div>
      <h2>Boss HP: {BossHP}</h2>
      <progress value={BossHP} max={sm.boss_stats.max_hp}></progress>
    </div>
  );
};

const ContextManagement = () => {
  const [BossHP, setBossHP] = useState(sm.boss_stats.hp);

  useEffect(() => {
    console.log('BossHP updated:', BossHP);
  }, [BossHP]);

  return (
    <BossContext.Provider value={{ BossHP, setBossHP }}>
      <PlayerMenu player="" isPlayerTurn={false} />
      <BossHpBar />
    </BossContext.Provider>
  );
};

export default function App() {
  return <ContextManagement />;
}
英文:

I created a simple working example based on your code, so when you click the button - the variable in the progress bar is updating.
You can check an example in playground here

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import React, { createContext, useState, useContext, useEffect } from &#39;react&#39;;
const sm = {
boss_stats: {
hp: 100,
max_hp: 200,
},
};
interface PlayerMenuProps {
player: string;
isPlayerTurn: boolean;
}
export const BossContext = createContext&lt;{
BossHP: number;
setBossHP: (value: number) =&gt; void;
}&gt;({
BossHP: sm.boss_stats.hp,
setBossHP: () =&gt; {},
});
const PlayerMenu: React.FC&lt;PlayerMenuProps&gt; = ({ player, isPlayerTurn }) =&gt; {
const { setBossHP } = useContext(BossContext);
const handleAttack = () =&gt; {
const new_hp = Math.max(0, Math.floor(Math.random() * 100));
setBossHP(new_hp);
};
return (
&lt;div&gt;
&lt;button onClick={handleAttack}&gt;Attack&lt;/button&gt;
&lt;/div&gt;
);
};
const BossHpBar = () =&gt; {
const { BossHP } = useContext(BossContext);
return (
&lt;div&gt;
&lt;h2&gt;Boss HP: {BossHP}&lt;/h2&gt;
&lt;progress value={BossHP} max={sm.boss_stats.max_hp}&gt;&lt;/progress&gt;
&lt;/div&gt;
);
};
const ContextManagement = () =&gt; {
const [BossHP, setBossHP] = useState(sm.boss_stats.hp);
useEffect(() =&gt; {
console.log(&#39;BossHP updated:&#39;, BossHP);
}, [BossHP]);
return (
&lt;BossContext.Provider value={{ BossHP, setBossHP }}&gt;
&lt;PlayerMenu player=&quot;&quot; isPlayerTurn={false} /&gt;
&lt;BossHpBar /&gt;
&lt;/BossContext.Provider&gt;
);
};
export default function App() {
return &lt;ContextManagement /&gt;;
}

<!-- end snippet -->

答案2

得分: 0

你需要在导入时在文件名后面添加文件扩展名,像这样:

import { createContext, useState, useEffect } from 'react.js';
import * as sm from './StatManagement.js';
import { PlayerMenu, BossHpBar, BossArea, MainPage } from './MainPage.js';
// 用于 boss 血量条

interface BossContextValue {
    BossHP: number;
    setBossHP: (value: number) => void;  // 接受一个数字的函数
}

export const BossContext = createContext<BossContextValue>({
    BossHP: sm.boss_stats.hp,
    setBossHP: () => { },
});

function ContextManagement() {

    const [BossHP, setBossHP] = useState(sm.boss_stats.hp);
    useEffect(() => {
        // 这不会触发
        console.log('BossHP 更新:', BossHP);
    }, [BossHP]);
    return (
        <BossContext.Provider value={{ BossHP, setBossHP }}>
            <PlayerMenu player='' isPlayerTurn={false} />
            <BossHpBar />
        </BossContext.Provider>
    )
}

export default ContextManagement;

我已经将代码部分翻译好,如有其他需要,请告诉我。

英文:

You Have to add the file extension name after the file name in import. Like this:

import { createContext, useState, useEffect } from &#39;react.js&#39;;
import * as sm from &#39;./StatManagement.js&#39;;
import { PlayerMenu, BossHpBar, BossArea, MainPage } from &#39;./MainPage.js&#39;;
//used for the boss hp bar
interface BossContextValue {
BossHP: number;
setBossHP: (value: number) =&gt; void;  // Function that takes a number
}
export const BossContext = createContext&lt;BossContextValue&gt;({
BossHP: sm.boss_stats.hp,
setBossHP: () =&gt; { },
});
function ContextManagement() {
const [BossHP, setBossHP] = useState(sm.boss_stats.hp);
useEffect(() =&gt; {
//This never triggers 
console.log(&#39;BossHP updated:&#39;, BossHP);
}, [BossHP]);
return (
&lt;BossContext.Provider value={{ BossHP, setBossHP }}&gt;
&lt;PlayerMenu player=&#39;&#39; isPlayerTurn={false} /&gt;
&lt;BossHpBar /&gt;
&lt;/BossContext.Provider&gt;
)
}
export default ContextManagement;

I made as javascript files.
if it is libraries you can replace it with the lib URL. Or use require if it is from npm.

huangapple
  • 本文由 发表于 2023年5月20日 23:25:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76295966.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定