Tengo un botón llamado descargar, es un componente. La funcionalidad está escrita en un contenedor.
Quiero que el botón esté oculto de forma predeterminada, a menos que la condición "(i === número)" sea verdadera en la función de descarga.
Sin embargo, es complicado, ya que esta condición solo se validará cuando haga clic en "descargar". No estoy seguro de cómo valido esta lógica de antemano para determinar si el botón debe mostrarse o no.
¿Puedes ayudarme? Estoy tratando de establecer un estado para mostrar el botón, pero no funciona.
Mi código básicamente se ve así:
envase:
state = { showButton: false, }; componentDidMount() { this.download(); }; download = async () => { const data = await this.props.client .query({ query: numberQuery, fetchPolicy: "no-cache", }) // retrive data from number query .... const contentData = data.data.content; // retrieve and format numbers const numbers = this.getNumbers(contentData); // call get number and get the individual number here const number = await this.getNumber(); numbers.forEach((i) => { // this is to check if numbers contain the number from getNumber(), if // number matches number in numbers if (i === number) { this.setState({ showButton: true, }); // call functions, start downloading }; }); }; render() { return ( {this.state.showButton ? <Download onStartDownload={() => this.download()} /> : null} ); };componente:
class Download extends Component { state = { startDownload: false, }; startDownload = () => { this.props.onStartDownload(); }; render() { return ( <Fragment> <Button id="download" onClick={this.startDownload} > Download </Button> </Fragment> ); }; };Si entiendo correctamente, su problema es que los números se recuperan (y, a su vez, se ejecuta la lógica para mostrar/ocultar el botón) solo después de hacer clic en el botón de descarga, pero desea que se ejecute lo antes posible (que es decir, en el soporte del componente).
En general, la obtención de datos en React está separada de la lógica del controlador de procesamiento/eventos. En su caso, una solución es obtener los datos cuando el componente se monta, guardarlos en estado (como numbers y campos number ), luego, al renderizar, verifique si el number está en la matriz de numbers .
Por ejemplo:
// Container component; child component remains the same state = { number: null, numbers: [] }; componentDidMount() { this.fetchNumbers(); this.fetchNumber(); }; async fetchNumbers() { const data = await this.props.client .query({ query: numberQuery, fetchPolicy: 'no-cache', }); // retrive data from number query .... const contentData = data.data.content; // retrieve and format numbers const numbers = this.getNumbers(contentData); this.setState({ numbers }); } async fetchNumber() { // Assuming this is another HTTP request or something similar const number = await this.getNumber(); this.setState({ number }); } download = async () => { // *only* downloading logic }; render() { const { number, numbers } = this.state; const showDownload = numbers.includes(number); return showDownload ? <Download onStartDownload={() => this.download()}/> : null; }; }Notas:
Array.includes() en lugar de un bucle Array.forEach() simplifica el código (¡y probablemente le ahorrará algunos errores en el futuro!)fetchNumbers() , que obtiene this.state.numbers , de fetchNumber() , que obtiene this.state.number , simplemente porque parecen dos partes separadas del estado (y por lo tanto obtenerlas de forma independiente es más eficiente); podría mejorarlo aún más haciendo que las dos funciones devuelvan los datos (en lugar de cambiar el estado), luego usando Promise.all() en componentDidMount() (lo dejé fuera por simplicidad).necesita un constructor en su componente de clase y para actualizar el estado necesita usar setState() , revise el código a seguir:
class Download extends react.Component { constructor() { super();// required this.state = { startDownload: false }; } startDownload = () => { this.setState((prevState) => ({ // I use prevState, to bring the previous state value startDownload: !prevState.startDownload // here the value is inverted })); }; render() { return ( <> // this is equivalent to the fragment <button id="download" onClick={this.startDownload}> Download </button> </> ); } }