Tengo un componente React, y dentro del render
método del componente tengo algo como esto:
render() {
return (
<div>
<div>
// removed for brevity
</div>
{ switch(...) {} }
<div>
// removed for brevity
</div>
</div>
);
}
Ahora el caso es que tengo dos div
elementos, uno en la parte superior y otro en la parte inferior, que están fijos. En el medio, quiero tener una declaración de cambio y, de acuerdo con un valor en mi estado, quiero representar un componente diferente. Básicamente, quiero que los dos div
elementos estén fijos siempre, y solo en el medio para representar un componente diferente cada vez. Estoy usando esto para implementar un procedimiento de pago de varios pasos). Sin embargo, como es el código actualmente, no funciona, ya que me da un error que dice que switch
es inesperado. ¿Alguna idea de cómo lograr lo que quiero?
return
declaración o incluso elrender
método para el caso. ¿Podría definir cada uno<div>
como una constante y luego usar elswitch
antes de sureturn
para determinar cuál<div>
debe renderizarse?div
en la parte superior e inferior, varias veces para cada caso deswitch
. O simplemente te entendí mal, tú ...let middleDiv = ...
y luego incluirlo{middleDiv}
en su JSX de retorno entre los dos<div>
s que ha codificado allí.Respuestas:
Prueba esto, que también es mucho más limpio: saca ese interruptor del render en una función y simplemente llámalo pasando los parámetros que quieras. Por ejemplo:
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> ); }
fuente
A diferencia de otras respuestas, preferiría incluir el "interruptor" en la función de renderizado. Deja más claro qué componentes se pueden renderizar en esa posición. Puede implementar una expresión similar a un interruptor utilizando un objeto javascript antiguo simple:
render () { return ( <div> <div> {/* removed for brevity */} </div> { { 'foo': <Foo />, 'bar': <Bar /> }[param] } <div> {/* removed for brevity */} </div> </div> ) }
fuente
<SearchResults />
o<NoResults />
. Si el estado de la vista debería representar<NoResults />
, es<SearchResults />
posible que no se compile porque depende de propiedades que aún no existen.||
lo siguiente:{ 'foo': <Foo />, 'bar': <Bar /> }[param] || <Baz />
Eso está sucediendo, porque la
switch
declaración es unastatement
, pero aquí javascript espera una expresión.Aunque, no se recomienda utilizar la declaración de cambio en una
render
método, puede utilizar la función de autoinvocación para lograr esto:render() { // Don't forget to return a value in a switch statement return ( <div> {(() => { switch(...) {} })()} </div> ); }
fuente
Hice esto dentro del método 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> ) }
Traté de mantener limpio el retorno de render (), así que puse mi lógica en una función 'const' justo arriba. De esta manera también puedo sangrar perfectamente mis cajas de interruptores.
fuente
head()
método de los componentes de mi ruta para inyectar los datosreact-helmet
en el encabezado de mi documentoLa respuesta de Lenkan es una gran solución.
<div> {{ beep: <div>Beep</div>, boop: <div>Boop</div> }[greeting]} </div>
Si necesita un valor predeterminado, incluso puede hacerlo
<div> {{ beep: <div>Beep</div>, boop: <div>Boop</div> }[greeting] || <div>Hello world</div>} </div>
Alternativamente, si eso no le parece bien, puede hacer algo como
<div> { rswitch(greeting, { beep: <div>Beep</div>, boop: <div>Boop</div>, default: <div>Hello world</div> }) } </div>
con
function rswitch (param, cases) { if (cases[param]) { return cases[param] } else { return cases.default } }
fuente
Una forma de representar una especie de cambio en un bloque de renderizado, usando operadores condicionales:
{(someVar === 1 && <SomeContent/>) || (someVar === 2 && <SomeOtherContent />) || (this.props.someProp === "something" && <YetSomeOtherContent />) || (this.props.someProp === "foo" && this.props.someOtherProp === "bar" && <OtherContentAgain />) || <SomeDefaultContent /> }
Debe asegurarse que las condiciones devuelvan estrictamente un booleano.
fuente
No soy un gran admirador de ninguna de las respuestas actuales, porque son demasiado detalladas o requieren que salte el código para comprender lo que está sucediendo.
Prefiero hacer esto de una manera más centrada en el componente de reacción, creando un archivo
<Switch/>
. El trabajo de este componente es tomar un accesorio y solo renderizar los niños cuyo accesorio hijo coincida con este. Entonces, en el ejemplo a continuación, he creado untest
accesorio en el interruptor y lo comparé con unvalue
accesorio en los niños, solo renderizando los que coinciden.Ejemplo:
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>
Puede hacer que el cambio sea tan simple o tan complejo como desee. No olvide realizar una verificación más sólida de los niños y sus apoyos de valor.
fuente
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 ! };
esa manera puede escribir:javascript <Switch test={true}> <Case value={true}> <ItAlwaysFeelsRightToBeTrue /> </Case> <Case value={false}> <FalseAlarm /> </Case> </Switch>
Qué tal si:
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> ); }
fuente
Puedes hacer algo como esto.
<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 /> } }
fuente
No puede tener un interruptor en el render. El enfoque psuedo-switch de colocar un objeto literal que accede a un elemento no es ideal porque hace que todas las vistas se procesen y eso puede resultar en errores de dependencia de accesorios que no existen en ese estado.
Aquí hay una forma limpia y agradable de hacerlo que no requiere que cada vista se renderice por adelantado:
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> )
Si sus condiciones para qué estado de vista se basan en más que una propiedad simple, como múltiples condiciones por línea, entonces una enumeración y una
getViewState
función para encapsular las condiciones es una buena manera de separar esta lógica condicional y limpiar su renderizado.fuente
Aquí hay un ejemplo de trabajo completo usando un botón para cambiar entre componentes
puede configurar un constructor de la siguiente manera
constructor(props) { super(props); this.state={ currentView: '' } }
entonces puedes renderizar componentes de la siguiente manera
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> ); }
}
Como puede ver, estoy usando un botón para cambiar entre estados.
fuente
Realmente me gustó la sugerencia en https://stackoverflow.com/a/60313570/770134 , así que la adapté a Typecript así
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>;
fuente
Este es otro enfoque.
render() { return {this[`renderStep${this.state.step}`]()} renderStep0() { return 'step 0' } renderStep1() { return 'step 1' }
fuente