Mam komponent React, a wewnątrz render
metody komponentu mam coś takiego:
render() {
return (
<div>
<div>
// removed for brevity
</div>
{ switch(...) {} }
<div>
// removed for brevity
</div>
</div>
);
}
Chodzi o to, że mam dwa div
elementy, jeden na górze i jeden na dole, które są naprawione. W środku chcę mieć instrukcję przełącznika i zgodnie z wartością w moim stanie chcę renderować inny komponent. Zasadniczo chcę, aby te dwa div
elementy były zawsze naprawione i tylko w środku, aby za każdym razem renderować inny komponent. Używam tego do implementacji wieloetapowej procedury płatności). Chociaż, podobnie jak kod, obecnie nie działa, ponieważ wyświetla mi błąd, mówiąc, że switch
jest to nieoczekiwane. Jakieś pomysły, jak osiągnąć to, czego chcę?
return
oświadczeniu ani nawetrender
metody w tej sprawie. Czy mógłbyś zdefiniować każdy<div>
jako stałą, a następnie użyćswitch
przed swoim,return
aby określić, który<div>
powinien być renderowany?div
na górze i na dole wiele razy dla każdego przypadkuswitch
. Albo po prostu źle zrozumiałem, ty ...let middleDiv = ...
a następnie dołączyć go{middleDiv}
do swojego powrotu JSX między dwoma<div>
kodami, które tam zakodowałeś.Odpowiedzi:
Spróbuj tego, co też jest o wiele czystsze: usuń ten przełącznik z renderowania w funkcji i po prostu wywołaj go, przekazując żądane parametry. Na przykład:
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> ); }
źródło
W przeciwieństwie do innych odpowiedzi, wolałbym wstawić „przełącznik” w funkcji renderowania. Wyjaśnia, jakie komponenty mogą być renderowane w tym miejscu. Możesz zaimplementować wyrażenie podobne do przełącznika, używając zwykłego starego obiektu javascript:
render () { return ( <div> <div> {/* removed for brevity */} </div> { { 'foo': <Foo />, 'bar': <Bar /> }[param] } <div> {/* removed for brevity */} </div> </div> ) }
źródło
<SearchResults />
lub<NoResults />
. Jeśli stan widoku powinien być renderowany<NoResults />
,<SearchResults />
może się nie kompilować, ponieważ zależy to od właściwości, które jeszcze nie istnieją.||
w następujący sposób:{ 'foo': <Foo />, 'bar': <Bar /> }[param] || <Baz />
Dzieje się tak, ponieważ
switch
instrukcja jest astatement
, ale tutaj javascript oczekuje wyrażenia.Chociaż nie jest zalecane używanie instrukcji switch w
render
metodzie, możesz użyć funkcji samo-wywoływania, aby to osiągnąć:render() { // Don't forget to return a value in a switch statement return ( <div> {(() => { switch(...) {} })()} </div> ); }
źródło
Zrobiłem to wewnątrz metody render ():
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> ) }
Próbowałem zachować czystość powrotu render (), więc umieściłem moją logikę w funkcji „const” tuż powyżej. W ten sposób mogę również starannie wciskać obudowy przełączników.
źródło
head()
metody komponentów mojej trasy, aby wstrzyknąć danereact-helmet
do nagłówka mojego dokumentuSposób reprezentowania rodzaju przełącznika w bloku renderowania przy użyciu operatorów warunkowych:
{(someVar === 1 && <SomeContent/>) || (someVar === 2 && <SomeOtherContent />) || (this.props.someProp === "something" && <YetSomeOtherContent />) || (this.props.someProp === "foo" && this.props.someOtherProp === "bar" && <OtherContentAgain />) || <SomeDefaultContent /> }
Należy upewnić się, że warunki ściśle zwracają wartość logiczną.
źródło
Odpowiedź lenkana to świetne rozwiązanie.
<div> {{ beep: <div>Beep</div>, boop: <div>Boop</div> }[greeting]} </div>
Jeśli potrzebujesz wartości domyślnej, możesz to zrobić
<div> {{ beep: <div>Beep</div>, boop: <div>Boop</div> }[greeting] || <div>Hello world</div>} </div>
Ewentualnie, jeśli to ci się nie podoba, możesz zrobić coś takiego
<div> { rswitch(greeting, { beep: <div>Beep</div>, boop: <div>Boop</div>, default: <div>Hello world</div> }) } </div>
z
function rswitch (param, cases) { if (cases[param]) { return cases[param] } else { return cases.default } }
źródło
Nie jestem wielkim fanem żadnej z aktualnych odpowiedzi, ponieważ są one albo zbyt szczegółowe, albo wymagają przeskakiwania po kodzie, aby zrozumieć, co się dzieje.
Wolę robić to w sposób bardziej skoncentrowany na komponencie reagowania, tworząc plik
<Switch/>
. Zadaniem tego komponentu jest pobranie właściwości i renderowanie tylko dzieci, których właściwość potomna pasuje do tego. W poniższym przykładzie utworzyłemtest
rekwizyt na przełączniku i porównałem go zvalue
rekwizytem na dzieciach, renderując tylko te, które pasują.Przykład:
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>
Możesz uczynić przełącznik tak prostym lub złożonym, jak tylko chcesz. Nie zapomnij przeprowadzić dokładniejszego sprawdzenia dzieci i ich wartości.
źródło
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 ! };
ten sposób możesz napisać:javascript <Switch test={true}> <Case value={true}> <ItAlwaysFeelsRightToBeTrue /> </Case> <Case value={false}> <FalseAlarm /> </Case> </Switch>
Co powiesz na:
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> ); }
źródło
Możesz zrobić coś takiego.
<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 /> } }
źródło
Nie możesz mieć przełącznika w renderowaniu. Podejście pseudoprzełącznika polegające na umieszczeniu literału obiektowego, który uzyskuje dostęp do jednego elementu, nie jest idealne, ponieważ powoduje przetwarzanie wszystkich widoków, co może powodować błędy zależności właściwości, które nie istnieją w tym stanie.
Oto ładny, czysty sposób na zrobienie tego, który nie wymaga wcześniejszego renderowania każdego widoku:
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> )
Jeśli twoje warunki, dla których stan widoku są oparte na więcej niż prostej właściwości - takiej jak wiele warunków w wierszu, to wyliczenie i
getViewState
funkcja hermetyzująca warunki są dobrym sposobem na oddzielenie tej logiki warunkowej i oczyszczenie renderowania.źródło
Oto pełny przykład roboczy z użyciem przycisku do przełączania między komponentami
możesz ustawić konstruktora w następujący sposób
constructor(props) { super(props); this.state={ currentView: '' } }
następnie możesz renderować komponenty w następujący sposób
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> ); }
}
Jak widać, używam przycisku do przełączania się między stanami.
źródło
Bardzo podobała mi się sugestia w https://stackoverflow.com/a/60313570/770134 , więc dostosowałem ją do Typescript w ten sposób
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>;
źródło
Nie byłem w pełni zadowolony z żadnej odpowiedzi. Ale mam kilka pomysłów z @Matt Way.
Oto moje rozwiązanie:
Definicje:
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: `${test}` }) || <Default key='default-key' casevalue={`${test}`} />; 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> ); }
Stosowanie:
<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}`} />
źródło
function Notification({ text, status }) { return ( <div> {(() => { switch (status) { case 'info': return <Info text={text} />; case 'warning': return <Warning text={text} />; case 'error': return <Error text={text} />; default: return null; } })()} </div> ); }
źródło
To jest inne podejście.
render() { return {this[`renderStep${this.state.step}`]()} renderStep0() { return 'step 0' } renderStep1() { return 'step 1' }
źródło