Ocultar / mostrar componentes em reagir nativo


143

Eu sou realmente novo no React Native e estou me perguntando como posso ocultar / mostrar um componente.
Aqui está o meu caso de teste:

<TextInput
    onFocus={this.showCancel()}
    onChangeText={(text) => this.doSearch({input: text})} />

<TouchableHighlight 
    onPress={this.hideCancel()}>
    <View>
        <Text style={styles.cancelButtonText}>Cancel</Text>
    </View>
</TouchableHighlight>

Eu tenho um TextInputcomponente, o que eu quero é mostrar TouchableHighlightquando a entrada obtém o foco e ocultar TouchableHighlightquando o usuário pressionar o botão Cancelar.

Não sei "acessar" o TouchableHighlightcomponente para ocultá-lo / mostrá-lo dentro das minhas funções showCancel/hideCancel.
Além disso, como ocultar o botão desde o início?


Respostas:


135

Eu faria algo assim:

var myComponent = React.createComponent({

    getInitialState: function () {
        return {
            showCancel: false,
        };
    },

    toggleCancel: function () {
        this.setState({
            showCancel: !this.state.showCancel
        });
    }

    _renderCancel: function () {
        if (this.state.showCancel) {
            return (
                <TouchableHighlight 
                    onPress={this.toggleCancel()}>
                    <View>
                        <Text style={styles.cancelButtonText}>Cancel</Text>
                    </View>
                </TouchableHighlight>
            );
        } else {
            return null;
        }
    },

    render: function () {
        return (
            <TextInput
                onFocus={this.toggleCancel()}
                onChangeText={(text) => this.doSearch({input: text})} />
            {this._renderCancel()}          
        );
    }

});

1
Muito obrigado por isso, apenas uma pequena alteração que eu precisava fazer: onFocus = {() => this.showCancel ()} isso precisa ser uma função de retorno de chamada.
Crysfel

3
Só funcionou para mim depois de mudar o return ''quereturn null
k7k0

33
Você também pode fazer {someBoolVal && <Component />}e ele só será exibido se o valor bool for verdadeiro.
Nathan Hyland

Esta é a melhor resposta
Kirill Gusyatin 28/12/16

3
Eu não sei que esta é a resposta aceita que não implementar o original desejada funcionalidade Show / Hide, mas em vez adicionar / remover
Muhammad Aref

150

Na sua função de renderização:

{ this.state.showTheThing && 
  <TextInput/>
}

Então faça:

this.setState({showTheThing: true})  // to show it  
this.setState({showTheThing: false}) // to hide it

2
Isso funcionou para mim. No entanto, não sei por que, quando faço algo como { this.state.showTheThing && (<Text>foo</Text> && <Text>bar</Text>)}apenas "barra" é mostrado na interface do usuário. Eu esperava que "foo" e "bar" fossem exibidos. O que eu precisava fazer para resolver isso é para chamar{ this.state.showTheThing && (<Text>foo</Text>} { this.state.showTheThing && (<Text>bar</Text>}
tonatiuhnb

2
talvez isso funcione? porque a lógica &&não combinam elementos{ this.state.showTheThing && (<View><Text>foo</Text><Text>bar</Text></View>)}
muescha

Isso funcionou para mim, eu queria mostrar o botão "Próximo passo" quando um usuário carregava a sua manicure de perfil. então meu código foi:{this.state.hasPic && <Button title="Go to next step" onPress={this._nextStep} />}
Daggie Blanqx - Douglas Mwangi

Para qualquer pessoa que tenha dificuldades em mostrar mais de um componente, envolva seu componente com um fragmento. por exemplo. <React.Fragment><Text>Foo</Text><Text>Bar></Text></React.Fragment>
Ben Cull

48

Ao reagir ou reagir de forma nativa, a maneira como o componente ocultar / mostrar ou adicionar / remover não funciona como no Android ou iOS. Muitos de nós pensam que haveria uma estratégia semelhante como

View.hide = true or parentView.addSubView(childView)

Mas a maneira como reage ao trabalho nativo é completamente diferente. A única maneira de obter esse tipo de funcionalidade é incluir seu componente no seu DOM ou remover do DOM.

Aqui neste exemplo, vou definir a visibilidade da exibição de texto com base no clique do botão.

insira a descrição da imagem aqui

A idéia por trás dessa tarefa é criar uma variável de estado chamada state, com o valor inicial definido como false quando o evento de clique no botão acontece e o valor alterna. Agora vamos usar essa variável de estado durante a criação do componente.

import renderIf from './renderIf'

class FetchSample extends Component {
  constructor(){
    super();
    this.state ={
      status:false
    }
  }

  toggleStatus(){
    this.setState({
      status:!this.state.status
    });
    console.log('toggle button handler: '+ this.state.status);
  }

  render() {
    return (
      <View style={styles.container}>
        {renderIf(this.state.status)(
          <Text style={styles.welcome}>
            I am dynamic text View
          </Text>
        )}

        <TouchableHighlight onPress={()=>this.toggleStatus()}>
          <Text>
            touchme
          </Text>
        </TouchableHighlight>
      </View>
    );
  }
}

a única coisa a ser observada nesse trecho é renderIfque, na verdade, é uma função que retornará o componente passado a ele com base no valor booleano passado a ele.

renderIf(predicate)(element)

renderif.js

'use strict';
const isFunction = input => typeof input === 'function';
export default predicate => elemOrThunk =>
  predicate ? (isFunction(elemOrThunk) ? elemOrThunk() : elemOrThunk) : null;

Inteligente :) qual é o caso de uso do thunk?
goldylucks

Haha Brilhante!
Jaseem Abbas 26/03

Essa solução faz sentido para casos de uso em que uma caixa de diálogo precisa renderizar somente quando necessário. Ty!
SoundStage

2
Isso não funcionará se você precisar manter o status, remova o elemento e redefina seu estado. portanto, cada vez que você renderiza novamente, é como criar novamente o componente.
Daniel Jose Padilla Peña

1
você precisa verificar este exemplo: Ocultar / Exibir componentes em reagir nativa
sumit kumar pradhan

20

em render (), você pode mostrar condicionalmente o JSX ou retornar nulo como em:

render(){
    return({yourCondition ? <yourComponent /> : null});
}

3
Parênteses deve ser exigido na linha 2.
jiexishede

Obrigado pela solução mais simples
Sam

13

Eu precisava alternar entre duas imagens. Com a troca condicional entre eles, houve um atraso de 5 segundos sem nenhuma imagem exibida.

Eu estou usando a abordagem da resposta amos downvoted. Postando como nova resposta, porque é difícil colocar o código em comentário com a formatação correta.

Função de renderização:

<View style={styles.logoWrapper}>
  <Image
    style={[styles.logo, loading ? styles.hidden : {}]}
    source={require('./logo.png')} />
  <Image
    style={[styles.logo, loading ? {} : styles.hidden]}
    source={require('./logo_spin.gif')} />
</View>

Estilos:

var styles = StyleSheet.create({
  logo: {
    width: 200,
    height: 200,
  },
  hidden: {
    width: 0,
    height: 0,
  },
});

screencast


Isso mantém os componentes na memória, o que pode ser um problema com grandes componentes. Por que não usar os ótimos exemplos acima? Eles vão inserir a imagem direita e remova o outro completamente ...
AS

4
qualquer um desses exemplos não funciona corretamente quando você tenta criar um spinner animado. Como eu já mencionei na minha resposta no android, tentando alternar img para anim gif, causará um atraso de 5s quando nenhum png nem gif for mostrado. Acredito que o atraso é causado pelo carregamento de gif na memória, o que pode levar algum tempo. No entanto, o iOS parece fazer um trabalho muito melhor aqui. Se você não acredita em mim, tente você mesmo.
precisa saber é o seguinte

1
Obviamente, como apontado, não é a solução ideal para todos os componentes. Mas IMHO para carregar spinner está tudo bem. Eventualmente, ele será descarregado quando o usuário fizer a transição para outra página.
Mauron85

13

Na maioria das vezes eu estou fazendo algo parecido com isto:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isHidden: false};
    this.onPress = this.onPress.bind(this);
  }
  onPress() {
    this.setState({isHidden: !this.state.isHidden})
  }
  render() {
    return (
      <View style={styles.myStyle}>

        {this.state.isHidden ? <ToHideAndShowComponent/> : null}

        <Button title={this.state.isHidden ? "SHOW" : "HIDE"} onPress={this.onPress} />
      </View>
    );
  }
}

Se você é iniciante em programação, essa linha deve ser estranha para você:

{this.state.isHidden ? <ToHideAndShowComponent/> : null}

Esta linha é equivalente a

if (this.state.isHidden)
{
  return ( <ToHideAndShowComponent/> );
}
else
{
  return null;
}

Mas você não pode escrever uma condição if / else no conteúdo JSX (por exemplo, a parte return () de uma função de renderização), portanto você precisará usar essa notação.

Esse pequeno truque pode ser muito útil em muitos casos, e eu sugiro que você o use em seus desenvolvimentos, porque você pode verificar rapidamente uma condição.

Saudações,


Você pode, por favor, explicar como você definiu <ToHideAndShowComponent />
Ritveak 25/02

12

insira a descrição da imagem aqui

Ocultar e mostrar a visualização principal deActivity Indicator

constructor(props) {
  super(props)

  this.state = {
    isHidden: false
  }  
} 

Ocultar e mostrar como seguir

{
   this.state.isHidden ?  <View style={style.activityContainer} hide={false}><ActivityIndicator size="small" color="#00ff00" animating={true}/></View> : null
}

Referência completa

render() {
    return (
       <View style={style.mainViewStyle}>
          <View style={style.signinStyle}>
           <TextField placeholder='First Name' keyboardType='default' onChangeFirstName={(text) => this.setState({firstName: text.text})}/>
           <TextField placeholder='Last Name' keyboardType='default' onChangeFirstName={(text) => this.setState({lastName: text.text})}/>
           <TextField placeholder='Email' keyboardType='email-address' onChangeFirstName={(text) => this.setState({email: text.text})}/>
           <TextField placeholder='Phone Number' keyboardType='phone-pad' onChangeFirstName={(text) => this.setState({phone: text.text})}/>
           <TextField placeholder='Password' secureTextEntry={true} keyboardType='default' onChangeFirstName={(text) => this.setState({password: text.text})}/>
           <Button  style={AppStyleSheet.buttonStyle} title='Sign up' onPress={() => this.onSignupPress()} color='red' backgroundColor='black'/>
          </View>
          {
            this.state.isHidden ?  <View style={style.activityContainer}><ActivityIndicator size="small" color="#00ff00" animating={true}/></View> : null
          }
      </View>
   );
}

O botão Ligar pressiona o estado definido da seguinte forma

onSignupPress() {
  this.setState({isHidden: true})
}

Quando você precisa se esconder

this.setState({isHidden: false})


10

Apenas use

style={ width:0, height:0 } // to hide

4
Seria útil se você adicionar algum contexto / detalhe à resposta.
UditS 07/02

Supondo que você tenha um mecanismo para decidir qual componente ocultar, essa resposta é bastante útil. Você pode agrupar qualquer componente que estiver tentando ocultar com uma View com style = {{width: 0, height: 0}}.
Josh Baker

6
como você restaura o elemento para a largura e altura originais?
Alguns Juan

4
não entendo por que isso é prejudicado, mas em muitos casos é um bom conselho. Preciso alternar entre gif animado e não animado. A troca condicional de img causou atrasos sem img na tela. Como parte da correção, estou exibindo os dois img, mas quem deve estar oculto tem largura e altura zero.
Mauron85 12/09/16

Isso mantém o componente na memória, o que pode ser um problema com grandes componentes. Por que não usar os ótimos exemplos acima? Eles inserir e remover componente completamente ...
AS

8
constructor(props) {
    super(props);
    this.state = {
      visible: true,
}
}

declarar visible como false, por padrão, modal / view são hide

exemplo = () => {

 this.setState({ visible: !this.state.visible })

}

** Chamada de função **

{this.state.visible == false ?
        <View>
            <TouchableOpacity
              onPress= {() => this.example()}>   // call function
                          <Text>
                            show view
                          </Text>
            </TouchableOpacity>

</View>
:
 <View>
    <TouchableOpacity
              onPress= {() => this.example()}>
                          <Text>
                            hide view
                          </Text>
            </TouchableOpacity>
</View> 
 }

6

Eu tive o mesmo problema em que gostaria de mostrar / ocultar as visualizações, mas realmente não queria que a interface do usuário pulasse quando as coisas fossem adicionadas / removidas ou necessariamente para lidar com a nova renderização.

Eu escrevi um componente simples para lidar com isso para mim. Animado por padrão, mas fácil de alternar. Coloquei no GitHub e NPM com um leia-me, mas todo o código está abaixo.

npm install --save react-native-hideable-view

import React, { Component, PropTypes } from 'react';
import { Animated  } from 'react-native';

class HideableView extends Component {
  constructor(props) {
    super(props);
    this.state = {
      opacity: new Animated.Value(this.props.visible ? 1 : 0)
    }
  }

  animate(show) {
    const duration = this.props.duration ? parseInt(this.props.duration) : 500;
    Animated.timing(
      this.state.opacity, {
        toValue: show ? 1 : 0,
        duration: !this.props.noAnimation ? duration : 0
      }
    ).start();
  }

  shouldComponentUpdate(nextProps) {
    return this.props.visible !== nextProps.visible;
  }

  componentWillUpdate(nextProps, nextState) {
    if (this.props.visible !== nextProps.visible) {
      this.animate(nextProps.visible);
    }
  }

  render() {
    if (this.props.removeWhenHidden) {
      return (this.visible && this.props.children);
    }
    return (
      <Animated.View style={{opacity: this.state.opacity}}>
        {this.props.children}
      </Animated.View>
    )
  }
}

HideableView.propTypes = {
  visible: PropTypes.bool.isRequired,
  duration: PropTypes.number,
  removeWhenHidden: PropTypes.bool,
  noAnimation: PropTypes.bool
}

export default HideableView;

Nice one, apenas o que eu estava procurando :)
Adamski

Isso funciona melhor, e se comporta como uma visão adequada quando você colocar outros componentes que têm um ciclo de vida dentro da vista (que não funciona com visible && (...).
dB.

6

Uma opção adicional é aplicar o posicionamento absoluto via estilo , configurando o componente oculto nas coordenadas fora da tela:

<TextInput
    onFocus={this.showCancel()}
    onChangeText={(text) => this.doSearch({input: text})}
    style={this.state.hide ? {position: 'absolute', top: -200} : {}}
/>

Diferentemente de algumas das sugestões anteriores, isso ocultaria seu componente da visualização, MAS também o renderizará (o manterá no DOM), tornando-o realmente invisível .


2
Essa ideia combina comigo, obrigado. Se alguém precisa, olhar para isso também: gist.github.com/jaysoo/cbb81a07cc22015a72e9
Chaki_Black

3

Se você precisar que o componente permaneça carregado, mas oculto, pode definir a opacidade para 0. (Eu precisava disso para a câmera expo, por exemplo)

//in constructor    
this.state = {opacity: 100}

/in component
style = {{opacity: this.state.opacity}}

//when you want to hide
this.setState({opacity: 0})


2

O exemplo a seguir está codificando em texto datilografado com Hooks.

import React, { useState, useEffect } from "react";

........

const App = () => {

   const [showScrollView, setShowScrollView] = useState(false);

   ......

   const onPress = () => {
    // toggle true or false
    setShowScrollView(!showScrollView);
  }

  ......

      </MapboxGL.ShapeSource>
        <View>{showScrollView ? (<DetailsScrollView />) : null}</View>
      </MapboxGL.MapView>
  ......

}

2
// You can use a state to control wether the component is showing or not
const [show, setShow] = useState(false); // By default won't show

// In return(
{
    show && <ComponentName />
}

/* Use this to toggle the state, this could be in a function in the 
main javascript or could be triggered by an onPress */

show == true ? setShow(false) : setShow(true)

// Example:
const triggerComponent = () => {
    show == true ? setShow(false) : setShow(true)
}

// Or
<SomeComponent onPress={() => {show == true ? setShow(false) : setShow(true)}}/>

3
Embora esse código possa resolver o problema do OP, é melhor incluir uma explicação sobre como o seu código soluciona o problema do OP. Dessa forma, futuros visitantes podem aprender com sua postagem e aplicá-la ao próprio código. O SO não é um serviço de codificação, mas um recurso para o conhecimento. Além disso, respostas completas de alta qualidade têm mais probabilidade de serem votadas. Esses recursos, juntamente com o requisito de que todas as postagens sejam independentes, são alguns dos pontos fortes do SO como plataforma, que o diferencia dos fóruns. Você pode editar para adicionar informações adicionais e / ou complementar suas explicações com a documentação de origem.
ysf

1
Atualizado, explicou um pouco mais. Espero que ajude!
Oyebola

0

Muito fácil. Basta alterar para () => this.showCancel () como abaixo:

<TextInput
        onFocus={() => this.showCancel() }
        onChangeText={(text) => this.doSearch({input: text})} />

<TouchableHighlight 
    onPress={this.hideCancel()}>
    <View>
        <Text style={styles.cancelButtonText}>Cancel</Text>
    </View>
</TouchableHighlight>


0

Estou apenas usando o método abaixo para ocultar ou exibir um botão. espero que ajude você. apenas atualizar o status e adicionar hide css é suficiente para mim

constructor(props) {
   super(props);
      this.state = {
      visibleStatus: false
   };
}
updateStatusOfVisibility () {
   this.setStatus({
      visibleStatus: true
   });
}
hideCancel() {
   this.setStatus({visibleStatus: false});
}

render(){
   return(
    <View>
        <TextInput
            onFocus={this.showCancel()}
            onChangeText={(text) => {this.doSearch({input: text}); this.updateStatusOfVisibility()}} />

         <TouchableHighlight style={this.state.visibleStatus ? null : { display: "none" }}
             onPress={this.hideCancel()}>
            <View>
                <Text style={styles.cancelButtonText}>Cancel</Text>
            </View>
        </TouchableHighlight>
     </View>)
}

0

Na verdade, no desenvolvimento do iOS, react-nativequando eu uso display: 'none'ou algo parecido abaixo:

const styles = StyleSheet.create({
  disappearImage: {
    width: 0,
    height: 0
  }
});

O iOS não carrega mais nada do componente Imagem, como o onLoadetc, então decidi usar algo como abaixo:

const styles = StyleSheet.create({
  disappearImage: {
    width: 1,
    height: 1,
    position: 'absolute',
    top: -9000,
    opacity: 0
  }
});

0

A única maneira de mostrar ou ocultar um componente no reagir nativo é verificar o valor de um parâmetro do estado do aplicativo como stateou props. Forneci um exemplo completo como abaixo:

import React, {Component} from 'react';
import {View,Text,TextInput,TouchableHighlight} from 'react-native'

class App extends Component {

    constructor(props){
        super(props);
        this.state={
            show:false
        }
}

    showCancel=()=>{
        this.setState({show:true})
    };

    hideCancel=()=>{
        this.setState({show:false})
    };

    renderTouchableHighlight(){
        if(this.state.show){
           return(
               <TouchableHighlight
                   style={{borderColor:'black',borderWidth:1,marginTop:20}}
                   onPress={this.hideCancel}>
                   <View>
                       <Text>Cancel</Text>
                   </View>
               </TouchableHighlight>
           )
        }
        return null;
    }

    render() {


        return (
            <View style={{justifyContent:'center',alignItems:'center',flex:1}}>
                <TextInput
                    style={{borderColor:'black',borderBottomWidth:1}}
                    onFocus={this.showCancel}
                />
                {this.renderTouchableHighlight()}

            </View>
        );
    }
}

export default App;

Aqui está o resultado


0

Se você deseja ocultá-lo, mas manter o espaço ocupado pelo componente, como a visibility: hiddenconfiguração de css no estilo do componente, opacity: 0faça o truque.

Dependendo do componente, outras etapas para desativar a funcionalidade podem ser necessárias, pois é possível a interação com um item invisível.


0

Você pode usar as condições para mostrar e ocultar os componentes

constructor(){

    super();

    this.state ={

      isVisible:true

    }
  }

  ToggleFunction = () => {

    this.setState(state => ({

      isVisible: !state.isVisible

    }));

  };

  render() {
  
    return (

      <View style={styles.MainContainer}>

      {

        this.state.isVisible ? <Text style= {{ fontSize: 20, color: "red", textAlign: 'center' }}> Hello World! </Text> : null
      }

      <Button title="Toggle Visibility" onPress={this.ToggleFunction} />

      </View>
    );
  }

-2
checkincheckout = () => {
        this.setState({ visible: !this.state.visible })
}

render() {
        return (
{this.state.visible == false ?
        <View style={{ alignItems: 'center', flexDirection: 'row', marginTop: 50 }}>

        <View style={{ flex: 1, alignItems: 'center', flexDirection: 'column' }}>

            <TouchableOpacity onPress={() => this.checkincheckout()}>

                <Text style={{ color: 'white' }}>Click to Check in</Text>

            </TouchableOpacity>

        </View>

    </View>
:
<View style={{ alignItems: 'center', flexDirection: 'row', marginTop: 50 }}>

<View style={{ flex: 1, alignItems: 'center', flexDirection: 'column' }}>

   <TouchableOpacity onPress={() => this.checkincheckout()}>

        <Text style={{ color: 'white' }}>Click to Check out</Text>

    </TouchableOpacity>

</View>

</View>
 }

);
}

Isso é tudo. aproveite sua codificação ...

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.