React 按钮和状态 - 如何避免状态过多?

React Buttons and State - how to avoid too many States?

我仍然是 React 的新手,还有很多东西要学。目前,我正在尝试制作一个页面,通过单击一个按钮来显示您想要的光剑和剑柄。我是通过使用状态来做到这一点的,从我目前拥有的状态数量来看,这似乎是错误的做法。

我是这样做的:我设置了一个状态并放置了一个 onClick 事件,该事件将所选 hilt/color 设置为 true,其余设置为 false,同时还呈现所述 hilt/color 的信息。它看起来像这样:

import { ReactComponent as QuiGon } from './qui-gon.svg';
import { ReactComponent as ObiWan } from './obi-wan.svg';
import { ReactComponent as ObiWanOld } from './obi-hilt-old.svg';
import { ReactComponent as DarthMaul } from './darth-maul-hilt.svg';
import { ReactComponent as AhsokaHilt } from './ahsoka-hilt.svg';
import { ReactComponent as AnakinHilt } from './anakin-hilt.svg';
import { ReactComponent as VaderHilt } from './darth-vader-hilt.svg';
import { ReactComponent as KyloHilt } from './kylo-ren-hilt.svg';
import './App.css';

function App() {
  
  const [nonChosen, setNonChosen] = useState(true);
  const [blue, setBlue] = useState(false);
  const [red, setRed] = useState(false);
  const [green, setGreen] = useState(false);
  const [purple, setPurple] = useState(false);
  const [yellow, setYellow] = useState(false);
  const [white, setWhite] = useState(false);

  const [saberOne, setSaberOne] = useState(true);
  const [doubleSaber, setDoubleSaber] = useState(false);
  const [quiGon, setQuiGon] = useState(false);
  const [obiWanNew, setObiWanNew] = useState(false);
  const [obiWanOld, setObiWanOld] = useState(false);
  const [ahsoka, setAhsoka] = useState(false);
  const [anakinHilt, setAnakinHilt] = useState(false);
  const [vaderHilt, setVaderHilt] = useState(false);
  const [kyloHilt, setKyloHilt] = useState(false);


  return (
    <div className="App">

          {/* Colors */}

          <button className="testsub" onClick={() => {setGreen(true); setWhite(false); setYellow(false); setPurple(false); setRed(false); setBlue(false); setNonChosen(false);}}>Green
          </button> 

          <button className="testsub" onClick={() => {setBlue(true); setWhite(false); setYellow(false); setPurple(false); setRed(false); setGreen(false); setNonChosen(false);}}>Blue
          </button>

          <button className="testsub" onClick={() => {setRed(true); setWhite(false); setYellow(false); setPurple(false); setBlue(false); setGreen(false); setNonChosen(false);}}>Red
          </button>

          <button className="testsub" onClick={() => {setPurple(true); setWhite(false); setYellow(false); setGreen(false);  setRed(false); setBlue(false); setNonChosen(false);}}>Purple
          </button> 

          <button className="testsub" onClick={() => {setYellow(true); setWhite(false); setPurple(false); setGreen(false);  setRed(false); setBlue(false); setNonChosen(false);}}>Yellow
          </button> 

          <button className="testsub" onClick={() => {setWhite(true); setYellow(false); setPurple(false); setGreen(false);  setRed(false); setBlue(false); setNonChosen(false);}}>White
          </button> 
          
          <br />

          {/* Hilts */}

          <button className="testsub" onClick={() => {setDoubleSaber(true); setKyloHilt(false); setVaderHilt(false); setAnakinHilt(false); setAhsoka(false); setSaberOne(false); setQuiGon(false); setObiWanNew(false); setObiWanOld(false);}}>Darth Maul
          </button>

          <button className="testsub" onClick={() => {setQuiGon(true); setKyloHilt(false); setVaderHilt(false); setAnakinHilt(false); setAhsoka(false); setDoubleSaber(false); setSaberOne(false); setObiWanNew(false); setObiWanOld(false);}}>Qui Gon
          </button>

          <button className="testsub" onClick={() => {setObiWanNew(true); setKyloHilt(false); setVaderHilt(false); setAnakinHilt(false); setAhsoka(false); setDoubleSaber(false); setSaberOne(false); setQuiGon(false); setObiWanOld(false);}}>Obi Wan
          </button>

          <button className="testsub" onClick={() => {setObiWanOld(true); setKyloHilt(false); setVaderHilt(false); setAnakinHilt(false); setAhsoka(false); setDoubleSaber(false); setSaberOne(false); setQuiGon(false); setObiWanNew(false);}}>Obi Wan Old
          </button>

          <button className="testsub" onClick={() => {setAhsoka(true); setKyloHilt(false); setVaderHilt(false); setAnakinHilt(false); setObiWanOld(false); setDoubleSaber(false); setSaberOne(false); setQuiGon(false); setObiWanNew(false);}}>Ahsoka Tano
          </button>

          <button className="testsub" onClick={() => {setAnakinHilt(true); setKyloHilt(false); setVaderHilt(false); setAhsoka(false); setObiWanOld(false); setDoubleSaber(false); setSaberOne(false); setQuiGon(false); setObiWanNew(false);}}>Anakin
          </button>

          <button className="testsub" onClick={() => {setVaderHilt(true); setKyloHilt(false); setAnakinHilt(false); setAhsoka(false); setObiWanOld(false); setDoubleSaber(false); setSaberOne(false); setQuiGon(false); setObiWanNew(false);}}>Vader
          </button>

          <button className="testsub" onClick={() => { setKyloHilt(true);setVaderHilt(false); setAnakinHilt(false); setAhsoka(false); setObiWanOld(false); setDoubleSaber(false); setSaberOne(false); setQuiGon(false); setObiWanNew(false);}}>Kylo
          </button>


<div class="lightsaber">
  <input type="checkbox" id="on-off" />
          {nonChosen && (
            <>
            <div className="blade colol"></div>
            {/* <div className="blade2 colol"></div> */}
            </>
          )}

          {blue && (
          <div className="blade colol2"></div>
          )}

          {red && (
          <div className="blade red-clr"></div>
          )}

          {green && (
          <div className="blade colol"></div>
          )}

          {purple && (
          <div className="blade purple-clr"></div>
          )}

          {yellow && (
          <div className="blade yellow-clr"></div>
          )}

          {white && (
          <div className="blade white-clr"></div>
          )}


        {saberOne && (
              <label className="hilt" for="on-off">
              <QuiGon />
            </label>
          )}

        {doubleSaber && (
          <>
            <div className="blade2 colol"></div>
            <label className="hilt" for="on-off">
              <DarthMaul />
            </label>
            </>
          )}

        {quiGon && (
              <label className="hilt" for="on-off">
              <QuiGon />
            </label>
          )}

        {obiWanNew && (
              <label className="hilt" for="on-off">
              <ObiWan />
            </label>
          )}

        {obiWanOld && (
              <label className="hilt" for="on-off">
              <ObiWanOld />
            </label>
          )}

        {ahsoka && (
              <label className="hilt" for="on-off">
              <AhsokaHilt />
            </label>
          )}

        {anakinHilt && (
              <label className="hilt" for="on-off">
              <AnakinHilt />
            </label>
          )}

        {vaderHilt && (
              <label className="hilt" for="on-off">
              <VaderHilt />
            </label>
          )}

        {kyloHilt && (
            //   <label className="hilt" for="on-off">
            //   <KyloHilt className="hilt2"/>
            // </label>
            <>
            <div className="blade3 colol"></div>
            <div className="blade4 colol"></div>
            <label className="hilt" for="on-off">
              <KyloHilt className="hilt2"/>
            </label>
            </>
          )}

</div>


<div className="infobox">
          {nonChosen && (
            <div>Yoyoyo</div>
          )}

          {blue && (
          <div>aasdsd</div>
          )}

          {green && (
          <div>fgfgfg</div>
          )}

</div>

    </div>
  );
}

export default App;

还没有完成所以有点乱,不过问题还是很不错的。我有很多状态,所有 setX(false) 按钮变得很长。

有什么更好的方法吗?我已经思考了很长时间关于如何使用 CSS、if/else 等,但我似乎无法理解如何让按钮显示一件事并离开休息隐藏,而不必像我已经那样过度指定它。我还是个新手,所以真的很感激任何帮助(再次对意大利面条代码感到抱歉)!

您可以初始化对象中的值并将它们用作初始状态

const initialValues = {
        nonChosen: true,
        blue: false,
        red: false,
        green: false,
        purple: false,
        yellow: false,
        white: false,
        // All other states in this or create a seperate object with seperate useState according to your wish
};

并将状态初始化为

  const [colors, setColors] = useState(initialValues);

将onClick期间的值设置为

  <button className="testsub" onClick={() => {setColors({...colors,green:true,white:false,yellow:false,purple:false,red:false,blue:false,nonchosen:false})>Green</button>

渲染期间:

{colors.nonChosen && (
            <>
            <div className="blade colol"></div>
            {/* <div className="blade2 colol"></div> */}
            </>
  )}

您可以使用 useReducer 钩子。 此外,您可以内联事件(用于颜色)或回调事件(用于刀柄)。 我用了两个案例。

const initialColorState = {
  nonChosen: false,
  blue: false,
  red: false,
  green: false,
  purple: false,
  yellow: false,
  white: false,
};

const initialHiltState = {
  saberOne: false,
  doubleSaber: false,
  quiGon: false,
  obiWanNew: false,
  obiWanOld: false,
  ahsoka: false,
  anakinHilt: false,
  vaderHilt: false,
  kyloHilt: false
}

function colorReducer(state, action) {
  switch (action.type) {
    case "Blue": {
      return {
        ...state,
        ...initialColorState,
        blue: true,
      }
    }
    case "Red": {
      return {
        ...state,
        ...initialColorState,
        red: true,
      }
    }
    case "Green": {
      return {
        ...state,
        ...initialColorState,
        green: true,
      }
    }
    case "Purple": {
      return {
        ...state,
        ...initialColorState,
        purple: true,
      }
    }
    case "Yellow": {
      return {
        ...state,
        ...initialColorState,
        yellow: true,
      }
    }
    case "White": {
      return {
        ...state,
        ...initialColorState,
        white: true,
      }
    }
  }
}

function hiltReducer(state, action) {
  switch (action.type) {
    case "DoubleSaber": {
      return {
        ...state,
        ...initialHiltState,
        doubleSaber: true,
      }
    }
    case "QuiGon": {
      return {
        ...state,
        ...initialHiltState,
        quiGon: true,
      }
    }
    case "ObiWanNew": {
      return {
        ...state,
        ...initialHiltState,
        obiWanNew: true,
      }
    }
    case "ObiWanOld": {
      return {
        ...state,
        ...initialHiltState,
        obiWanOld: true,
      }
    }
    case "Ahsoka": {
      return {
        ...state,
        ...initialHiltState,
        ahsoka: true,
      }
    }
    case "Anakin": {
      return {
        ...state,
        ...initialHiltState,
        anakinHilt: true,
      }
    }
    case "Vader": {
      return {
        ...state,
        ...initialHiltState,
        vaderHilt: true,
      }
    }
    case "Kylo": {
      return {
        ...state,
        ...initialHiltState,
        kyloHilt: true,
      }
    }
  }
}

function App() {
  const [colorState, colorDispatch] = useReducer(colorReducer, initialColorState)
  const [hiltState, hiltDispatch] = useReducer(hiltReducer, initialHiltState);

  const onHiltClick = useCallback((event) => {
    hiltDispatch({type: event.value});
  }, [hiltDispatch]);
  
  return (
    <div className="App">
      {/* Colors */}

      <button
        className="testsub"
        onClick={() => {
          colorDispatch({ type: "Green" })
        }}
      >
        Green
      </button>

      <button
        className="testsub"
        onClick={() => {
          colorDispatch({ type: "Blue" })
        }}
      >
        Blue
      </button>

      <button
        className="testsub"
        onClick={() => {
          colorDispatch({ type: "Red" })
        }}
      >
        Red
      </button>

      <button
        className="testsub"
        onClick={() => {
          colorDispatch({ type: "Purple" })
        }}
      >
        Purple
      </button>

      <button
        className="testsub"
        onClick={() => {
          colorDispatch({ type: "Yellow" })
        }}
      >
        Yellow
      </button>

      <button
        className="testsub"
        onClick={() => {
          colorDispatch({ type: "White" })
        }}
      >
        White
      </button>

      <br />

      {/* Hilts */}

      <button className="testsub" onClick={onHiltClick} value="DoubleSaber">
        Darth Maul
      </button>

      <button className="testsub" onClick={onHiltClick} value="QuiGon">
        Qui Gon
      </button>

      <button className="testsub" onClick={onHiltClick} value="ObiWanNew">
        Obi Wan
      </button>

      <button className="testsub" onClick={onHiltClick} value="ObiWanOld">
        Obi Wan Old
      </button>

      <button className="testsub" onClick={onHiltClick} value="Ahsoka">
        Ahsoka Tano
      </button>

      <button className="testsub" onClick={onHiltClick} value="Anakin">
        Anakin
      </button>

      <button className="testsub" onClick={onHiltClick} value="Vader">
        Vader
      </button>

      <button className="testsub" onClick={onHiltClick} value="Kylo">
        Kylo
      </button>

      .....
  )
}

export default App;