Bir React bileşeni içinde switch deyimi nasıl kullanılır?


111

Bir React bileşenim var ve bileşenin renderyönteminin içinde şöyle bir şey var:

render() {
    return (
        <div>
            <div>
                // removed for brevity
            </div>

           { switch(...) {} }

            <div>
                // removed for brevity
            </div>
        </div>
    );
}

Şimdi mesele şu ki div, biri üstte diğeri altta sabit olan iki öğem var. Ortada bir switch ifadesine sahip olmak istiyorum ve durumumdaki bir değere göre farklı bir bileşen oluşturmak istiyorum. Temel olarak, iki divöğenin her zaman sabitlenmesini ve tam ortada her seferinde farklı bir bileşen oluşturmasını istiyorum. Bunu çok adımlı bir ödeme prosedürü uygulamak için kullanıyorum). Yine de, şu anda kod gibi çalışmıyor, çünkü bana switchbunun beklenmedik olduğunu söyleyen bir hata veriyor . İstediğime nasıl ulaşacağıma dair bir fikrin var mı?


1
İfadede tüm bu mantığa returnveya renderbu konudaki yönteme sahip olmanıza gerek yok . Her tanımlamak Could <div>bir const olarak ve ardından kullanmak switch önce senin returnbelirlemek için <div>oluşturulması gereken?
Jared Goguen

@JaredGoguen Ama o zaman, divher durumda birden çok kez üstte ve altta tekrar etmem gerekir switch. Ya da sadece yanlış anladım, sen ..
Yazım hatası

hayır, için kod oluşturabilir let middleDiv = ...ve sonra orada sabit kodladığınız {middleDiv}iki URL arasına dönüş JSX'inizi ekleyebilirsiniz <div>.
Jared Goguen

Yanıtlar:


201

Şunu deneyin, ki bu da çok daha temiz: Bir işlevdeki o anahtarı render'dan çıkarın ve sadece istediğiniz parametreleri geçirme olarak adlandırın. Örneğin:

renderSwitch(param) {
  switch(param) {
    case 'foo':
      return 'bar';
    default:
      return 'foo';
  }
}

render() {
  return (
    <div>
      <div>
          // removed for brevity
      </div>
      {this.renderSwitch(param)}
      <div>
          // removed for brevity
      </div>
    </div>
  );
}


94

Diğer cevapların aksine, render fonksiyonunda "switch" i satır içi yapmayı tercih ederim. Bu konumda hangi bileşenlerin işlenebileceğini daha net hale getirir. Düz, eski bir javascript nesnesi kullanarak anahtar benzeri bir ifade uygulayabilirsiniz:

render () {
  return (
    <div>
      <div>
        {/* removed for brevity */}
      </div>
      {
        {
          'foo': <Foo />,
          'bar': <Bar />
        }[param]
      }
      <div>
        {/* removed for brevity */}
      </div>
    </div>
  )
}

1
bu çok havalı. Bir POJO yerine bir dizi kullanmak için onu biraz değiştirdim ve diziyi parantez içine almak için dizini kullanıyorum.
Nicholas Gentile

1
Python'da anahtar durumu işlemenin standart yolu budur. Üstün okunabilirliği nedeniyle bu durumda daha çok seviyorum.
Şapkamı Eat edeceğiz

12
Bu yaklaşımın sınırları ve ek yükü vardır. Görünümlerinizin her biri işlenecek ve mevcut olmayan mevcut duruma / props'a bağlı olacaktır. Ör:: <SearchResults />veya render etmek istediğinizi varsayalım <NoResults />. Görünüm durumunun oluşturulması gerekiyorsa <NoResults />, <SearchResults />henüz var olmayan özelliklere bağlı olduğu için derlenmeyebilir.
ABCD.ca

3
Varsayılan durum nedir?
kungfooman

4
@ lama12345 Varsayılan durum için ||aşağıdaki gibi kullanın :{ 'foo': <Foo />, 'bar': <Bar /> }[param] || <Baz />
Aaron Adrian

55

Bu oluyor çünkü switchifade bir statement, ama burada javascript bir ifade bekliyor.

Bir renderyöntemde switch ifadesinin kullanılması tavsiye edilmese de, bunu başarmak için kendi kendini çağıran işlevi kullanabilirsiniz:

render() {
    // Don't forget to return a value in a switch statement
    return (
        <div>
            {(() => {
                switch(...) {}
            })()}
        </div>
    );
}

Teşekkürler şunu kullandım: render () {return (<div> {(() => {switch (this.state.type) {case commons.HARD_SOFT: return <HardSoft params = {this.state.param} onSubmitHead = {this.onSubmit} />;}}) ()} </div>);
JhonQO

22

Bunu render () yöntemi içinde yaptım:

  render() {
    const project = () => {
      switch(this.projectName) {

        case "one":   return <ComponentA />;
        case "two":   return <ComponentB />;
        case "three": return <ComponentC />;
        case "four":  return <ComponentD />;

        default:      return <h1>No project match</h1>
      }
    }

    return (
      <div>{ project() }</div>
    )
  }

Render () dönüşünü temiz tutmaya çalıştım, bu yüzden mantığımı hemen yukarıdaki 'const' işlevine koydum. Bu şekilde, anahtar durumlarımı da düzgün bir şekilde girebilirim.


@a_m_dev Render metodunun içindeki bir 'const project' fonksiyonu yerine, onu bir bileşen metodu olarak yerleştirebiliriz, sonra onu render return içinde "<div> {this.project ()} </div>" gibi çağırabiliriz. Switch'i hiç kullanmadığınızdan bahsetmiyorsanız, if / else kullanmayı veya durumu güncelleyerek className kullanarak bileşenleri göstermeyi / gizlemeyi düşünebilirim.
williamsi

bu daha da iyi olabilir, çünkü örneğin head()verileri react-helmet
belgemin

15

lenkan'ın cevabı harika bir çözüm.

<div>
  {{ beep: <div>Beep</div>,
     boop: <div>Boop</div>
  }[greeting]}
</div>

Varsayılan bir değere ihtiyacınız varsa, bunu bile yapabilirsiniz.

<div>
  {{ beep: <div>Beep</div>,
     boop: <div>Boop</div>
  }[greeting] || <div>Hello world</div>}
</div>

Alternatif olarak, bu size pek iyi gelmiyorsa, o zaman

<div>
  { 
    rswitch(greeting, {
      beep: <div>Beep</div>,
      boop: <div>Boop</div>,
      default: <div>Hello world</div>
    }) 
  }
</div>

ile

function rswitch (param, cases) {
  if (cases[param]) {
    return cases[param]
  } else {
    return cases.default
  }
}

2
{{key1: <Component1 />, ...} [key] iyi bir çözüm değil. Görüyorsunuz, seçim gerçekleşmeden önce, ilk nesnenin tamamı oluşturulur - yani, anahtarın her dalı işlenir -
Bileşen1, Bileşen2

Evet, lenkan'ın cevabı doğru cevap olmalı, çünkü fonksiyonel bileşende switch kullanılmamalıdır. Varsayılan durum için OR eklediğiniz için teşekkür ederiz . Ve rswitch () ile uğraşmayın, harita çözümü yerinde! başparmak yukarı
Eugenijus S.

15

Koşullu işleçleri kullanarak bir oluşturma bloğundaki bir tür anahtarı temsil etmenin bir yolu :

{(someVar === 1 &&
    <SomeContent/>)
|| (someVar === 2 &&
    <SomeOtherContent />)
|| (this.props.someProp === "something" &&
    <YetSomeOtherContent />)
|| (this.props.someProp === "foo" && this.props.someOtherProp === "bar" &&
    <OtherContentAgain />)
||
    <SomeDefaultContent />
}

Koşulların kesinlikle bir boole değeri döndürmesi sağlanmalıdır.


2
Güzel ve zariftir ve doğrudan render bloğunda kullanılabilir. En iyi cevap IMHO
GavinBelson

2
Bunun EsLints kurallarının ihlali olduğunu fark ettim eslint.org/docs/rules/no-mixed-operators mixed && and ||
fishfingers

1
@FishFingers Bunu da aynen yukarıdaki gibi kullanmaya çalıştığımda fark ettim. Her "vakayı" parantez içine alarak kolayca önlenebilir.
Ch0sen

13

Mevcut cevapların hiçbirinin büyük bir hayranı değilim, çünkü ya çok ayrıntılılar ya da neler olduğunu anlamak için kodun etrafından dolaşmanızı gerektiriyorlar.

Bunu daha tepkisel bileşen merkezli, bir <Switch/>. Bu bileşenin görevi, bir destek almak ve yalnızca çocuk pervanesi bununla eşleşen çocukları oluşturmaktır. Bu nedenle, aşağıdaki örnekte test, anahtar üzerinde bir destek oluşturdum ve bunu valueçocuklar üzerindeki bir destekle karşılaştırdım , yalnızca eşleşenleri oluşturdum.

Misal:

const Switch = props => {
  const { test, children } = props
  // filter out only children with a matching prop
  return children.find(child => {
    return child.props.value === test
  })      
}

const Sample = props => {
  const someTest = true
  return (
    <Switch test={someTest}>
      <div value={false}>Will display if someTest is false</div>
      <div value={true}>Will display if someTest is true</div>
    </Switch>
  )
}

ReactDOM.render(
  <Sample/>,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Geçişi istediğiniz kadar basit veya karmaşık yapabilirsiniz. Çocukları ve değerli eşyalarını daha sağlam bir şekilde kontrol etmeyi unutmayın.


3
Tam olarak aradığım şey! İşte küçük bir gelişme: javascript const Switch = props => { const { test, children } = props; return children.find(child => { return child.props.value === test; }); }; const Case = ({ children, value }) => { return children; // I don't want do add container around my cases ! }; Bu şekilde yazabilirsiniz:javascript <Switch test={true}> <Case value={true}> <ItAlwaysFeelsRightToBeTrue /> </Case> <Case value={false}> <FalseAlarm /> </Case> </Switch>
lsmod

Bu iyi bir çözüm olsa da, koda bir açıklama eklemek onu daha da iyi hale
getirebilirdi

@papigee Biraz daha ayrıntılı güncellendi.
Matt Way

@MattWay Bu, saf JS için iyi bir seçenek olsa da, ReactNode'da özellik bulma bulunmadığından hedef es5 olarak ayarlandığında bir TS hatası atıyor
Zakriya Bilal

@ZakriyaBilal Kod, daha çok bir kavram kanıtıdır ve anahtarlar gibi fikirlerin bileşenleştirilmesinin kodunuzun nasıl daha fazla tepki vermesini sağlayacağı ile ilgilidir. Anahtar, çocukların sahne malzemelerini karşılaştırmanın bir yolunu bulmak.
Matt Yolu

3

Peki ya:

mySwitchFunction = (param) => {
   switch (param) {
      case 'A':
         return ([
            <div />,
         ]);
      // etc...
   }
}
render() {
    return (
       <div>
          <div>
               // removed for brevity
          </div>

          { this.mySwitchFunction(param) }

          <div>
              // removed for brevity
          </div>
      </div>
   );
}

2

Bunun gibi bir şey yapabilirsiniz.

 <div>
          { object.map((item, index) => this.getComponent(item, index)) }
 </div>

getComponent(item, index) {
    switch (item.type) {
      case '1':
        return <Comp1/>
      case '2':
        return <Comp2/>
      case '3':
        return <Comp3 />
    }
  }

2

Oluşturmada bir anahtarınız olamaz. Bir öğeye erişen bir nesne-değişmezi yerleştirmenin psuedo-switch yaklaşımı ideal değildir, çünkü tüm görünümlerin işlenmesine neden olur ve bu durumda bulunmayan prop'ların bağımlılık hatalarına neden olabilir.

Her görünümün önceden oluşturulmasını gerektirmeyen, bunu yapmanın güzel ve temiz bir yolu:

render () {
  const viewState = this.getViewState();

  return (
    <div>
      {viewState === ViewState.NO_RESULTS && this.renderNoResults()}
      {viewState === ViewState.LIST_RESULTS && this.renderResults()}
      {viewState === ViewState.SUCCESS_DONE && this.renderCompleted()}
    </div>
  )

Görünüm durumu için koşullarınız, satır başına birden çok koşul gibi basit bir özelliğe dayanıyorsa, getViewStatebu koşullu mantığı ayırmak ve renderınızı temizlemek için bir enum ve koşulları kapsayacak bir işlev güzel bir yoldur.


Basit ve temiz bir yol.
Abhilekh Singh

2

İşte bileşenler arasında geçiş yapmak için bir düğme kullanan tam bir çalışma örneği

bir yapıcıyı aşağıdaki gibi ayarlayabilirsiniz

constructor(props)
{
    super(props);
    this.state={
        currentView: ''
    }
}

daha sonra bileşenleri aşağıdaki gibi oluşturabilirsiniz

  render() 
{
    const switchView = () => {

    switch(this.state.currentView) 
    {

      case "settings":   return <h2>settings</h2>;
      case "dashboard":   return <h2>dashboard</h2>;

      default:      return <h2>dashboard</h2>
    }
  }

    return (

       <div>

            <button onClick={(e) => this.setState({currentView: "settings"})}>settings</button>
            <button onClick={(e) => this.setState({currentView: "dashboard"})}>dashboard</button>

            <div className="container">
                { switchView() }
            </div>


        </div>
    );
}

}

Gördüğünüz gibi, durumlar arasında geçiş yapmak için bir düğme kullanıyorum.


1

Https://stackoverflow.com/a/60313570/770134 adresindeki öneriyi gerçekten beğendim , bu yüzden onu Typecript'e uyarladım

import React, { FunctionComponent } from 'react'
import { Optional } from "typescript-optional";
const { ofNullable } = Optional

interface SwitchProps {
  test: string
  defaultComponent: JSX.Element
}

export const Switch: FunctionComponent<SwitchProps> = (props) => {
  return ofNullable(props.children)
    .map((children) => {
      return ofNullable((children as JSX.Element[]).find((child) => child.props['value'] === props.test))
        .orElse(props.defaultComponent)
    })
    .orElseThrow(() => new Error('Children are required for a switch component'))
}

const Foo = ({ value = "foo" }) => <div>foo</div>;
const Bar = ({ value = "bar" }) => <div>bar</div>;
const value = "foo";
const SwitchExample = <Switch test={value} defaultComponent={<div />}>
  <Foo />
  <Bar />
</Switch>;

0

Cevapların hiçbirinden kesinlikle memnun değildim. Ancak @ Matt Way'den bazı fikirler aldım.

İşte benim çözümüm:

Tanımlar:

const Switch = props => {
    const { test, children = null } = props;
    return children && children.find(child => child && child.props && child.props.casevalue === test) || null;
}

const Case = ({ casevalue = false, children = null }) => <div casevalue={`${casevalue}`}>{children}</div>;

Case.propTypes = {
    casevalue: PropTypes.string.isRequired,
    children: PropTypes.node.isRequired,
}

const Default = ({ children }) => children || <h1>NO_RESULT</h1>;

const SwitchCase = ({ test, cases = [], defaultValue = null }) => {

    const defaultVal = defaultValue
        && React.cloneElement(defaultValue, { key: 'default-key', casevalue: `${true}` })
        || <Default key='default-key' casevalue={`${true}`} />;

    return (
        <Switch test={`${test}`} >
            {
                cases.map((cas, i) => {
                    const { props = {} } = cas || {};
                    const { casevalue = false, ...rest } = props || {};

                    return <Case key={`case-key-${i}`} casevalue={`${casevalue}`}>{ React.cloneElement(cas, rest)}</Case>
                })
                .concat(defaultVal)
            }
        </Switch>
    );
}

Kullanım:

<SwitchCase
  cases={[
    <div casevalue={`${false}`}>#1</div>,
    <div casevalue={`${true}`}>#2</div>,
    <div casevalue={`${false}`}>#3</div>,
  ]}
  defaultValue={<h1>...nothing to see here</h1>} // You can leave it blank.
  test={`${true}`}
/>

-1

Bu başka bir yaklaşımdır.

render() {
   return {this[`renderStep${this.state.step}`]()}

renderStep0() { return 'step 0' }
renderStep1() { return 'step 1' }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.