渲染后状态设置为初始值

时间:2021-05-12 17:43:45

标签: javascript reactjs react-native

这是我的情况:我有一个带有一些状态的组件。其中一个(documents)用于存储组件列表的数据,因此状态是一个对象数组。

按钮向 API 发出请求,该请求会删除系统上的某个组件。在请求之后,我想从状态中删除这个元素。我已经使用过滤器实现了这个(函数 removeDocument),该过滤器返回一个在 setDocuments 中用作参数的数组。开发这个我注意到状态 documents 是空的。 如果我没有在任何地方调用 setDocuments,为什么会发生这种情况?

组件代码:

import React, { useState, useEffect, useContext } from "react";
import { KeyboardAvoidingView, View, Image, Text, InteractionManager, ActivityIndicator, TouchableOpacity } from "react-native";
import styles from './style';
import mainStyles from '../../style';
import UserInfo from '../../../../config/context';
import { AcademicCapOutline, BanOutline, BriefcaseOutline, CalendarOutline, CashOutline, CheckCircleOutline, DocumentDuplicateOutline, EyeOutline, FingerPrintOutline, FlagOutline, HeartOutline, Home, HomeOutline, IdentificationOutline, InboxIn, InboxInOutline, LinkOutline, MailOutline, MapOutline, OfficeBuildingOutline, PencilAlt, PhoneIncomingOutline, PhoneOutline, Trash, ViewGridAdd } from 'react-native-heroicons';
import ButtonsRow from '../../../components/buttons/row/buttonsRow';
import ListTitle from '../../../components/listTitle/listTitle';
import { ScrollView } from "react-native-gesture-handler";
import DocumentList from '../../../components/documents/documentList';
import DataList from '../../../components/list/dataList/dataList';
import { getUsers, getDocument, deleteDocument } from './api';
import Popup from '../../popup/popup';
import DocumentPopup from '../../popup/document/document';
import { useCallback } from "react";

const PersonScreen = (props) => {

  const { user, refreshToken } = useContext(UserInfo);
  const [buttons, setButtons] = useState([]);
  const [documents, setDocuments] = useState([]);
  const [data, setData] = useState([]);
  const [name, setName] = useState('');
  const [popup, setPopup] = useState({open: false});

  useEffect(() => {
    
    let b = [];

    if(user.rol != 'I' && user.rol != 'P'){

      if(user.rol == 'G')
        b.push({key: '3', icon: ViewGridAdd, action: () => console.log('hola')});

      if(user.rol == 'A')
        b = b.concat([
          {key: '1', icon: PencilAlt, action: () => console.log('hola')},
          {key: '2', icon: Home, action: () => console.log('hola')},
          {key: '3', icon: ViewGridAdd, action: () => console.log('hola')},
          {key: '4', icon: InboxIn, action: () => console.log('hola')},
          {key: '5', icon: Trash, action: () => console.log('hola')},
        ])

    }

    setButtons(b);

    var interaction = InteractionManager.runAfterInteractions( () => {
    
      getUsers(user, refreshToken, props.id)
      .then(data => {

        setName(data.nombre);

        // Set Documents
        if(data.documentos){
          setDocuments(data.documentos.map( d => {
            return { ruta: d.ruta, title: d.documento.nombre, size: d.documento.tamano, type: 'Document', onPress: () => { openDocument( d.ruta, d.documento.nombre ) } }
          }))
        }

        // Set Data
        let d = [];

        if(data.activo != undefined)
          d.push({ key: 'activo', icon: CheckCircleOutline, title:"Estado", data: ( data.activo ? 'Alta' : 'Baja' )})

        if(data.email)
          d.push({ key: 'email', icon: MailOutline, title:"Dirección de email", data: data.email})

        if(data.documento_id)
          d.push({ key: 'documento_id', icon: IdentificationOutline, title:"Documento de identificación", data:data.documento_id})

        if(data.tipo_documento_id)
          d.push({ key: 'tipo_documento_id', icon: IdentificationOutline, title:"Tipo de documento de identificación", data:data.tipo_documento_id})

        if(data.fecha_nacimiento)
          d.push({ key: 'fecha_nacimiento', icon: CalendarOutline, title:"Fecha de nacimiento", data:data.fecha_nacimiento})

        if(data.genero)
          d.push({ key: 'genero', icon: FingerPrintOutline, title:"Genero", data:data.genero})

        if(data.direccion)
          d.push({ key: 'direccion', icon: MapOutline, title:"Dirección", data:data.direccion})

        if(data.ciudad)
          d.push({ key: 'ciudad', icon: OfficeBuildingOutline, title:"Ciudad", data:data.ciudad})

        if(data.pais)
          d.push({ key: 'pais', icon: FlagOutline, title:"País", data:data.pais})        

        if(data.telefono)
          d.push({ key: 'telefono', icon: PhoneOutline, title:"Teléfono", data:data.telefono})

        if(data.pais_nacimiento)
          d.push({ key: 'pais_nacimiento', icon: FlagOutline, title:"País de nacimiento", data:data.pais_nacimiento})

        if(data.pais_procedencia)
          d.push({ key: 'pais_procedencia', icon: FlagOutline, title:"País de procedencia", data:data.pais_procedencia})
        
        if(data.estado_civil)
          d.push({ key: 'estado_civil', icon: LinkOutline, title:"Estado civil", data:data.estado_civil})

        if(data.formacion)
          d.push({ key: 'formacion', icon: AcademicCapOutline, title:"Formación", data:data.formacion})
        
        if(data.ocupacion)
          d.push({ key: 'ocupacion', icon: BriefcaseOutline, title:"Ocupación", data:data.ocupacion})

        if(data.permiso_trabajo != undefined)
          d.push({ key: 'permiso_trabajo', icon: BanOutline, title:"Permiso de trabajo", data: ( data.ocupacion ? 'Sí' : 'No' )})
          
        if(data.estado_documentacion)
          d.push({ key: 'estado_documentacion', icon: BriefcaseOutline, title:"Estado de la documentación", data:data.estado_documentacion})

        if(data.estado_empadronamiento)
          d.push({ key: 'estado_empadronamiento', icon: DocumentDuplicateOutline, title:"Estado de empadronamiento", data:data.estado_empadronamiento})

        if(data.tarjeta_sanitaria)
          d.push({ key: 'tarjeta_sanitaria', icon: HeartOutline, title:"Estado de tarjeta sanitaria", data:data.tarjeta_sanitaria})

        if(data.observaciones)
          d.push({ key: 'observaciones', icon: EyeOutline, title:"Observaciones", data:data.observaciones})

        if(data.cuota)
          d.push({ key: 'cuota', icon: CashOutline, title:"Cuota", data: `${data.cuota} €`})

        if(data.newsletter != undefined)
          d.push({ key: 'newsletter', icon: InboxInOutline, title:"Quiere newsletter", data: ( data.newsletter ? 'Sí' : 'No' )})

        if(data.disponibilidad_mananas != undefined)
          d.push({ key: 'disponibilidad_mananas', icon: CalendarOutline, title:"Disponibilidad de mañanas", data: ( data.disponibilidad_mananas ? 'Sí' : 'No' )})

        if(data.disponibilidad_tardes != undefined)
          d.push({ key: 'disponibilidad_tardes', icon: CalendarOutline, title:"Disponibilidad de tardes", data: ( data.disponibilidad_tardes ? 'Sí' : 'No' )})

        if(data.disponibilidad_fines_de_semana != undefined)
          d.push({ key: 'disponibilidad_fines_de_semana', icon: CalendarOutline, title:"Disponibilidad en fin de semana", data: ( data.disponibilidad_fines_de_semana ? 'Sí' : 'No' )})

        if(data.experiencia_previa)
          d.push({ key: 'experiencia_previa', icon: EyeOutline, title:"Experiencia previa", data:data.experiencia_previa})

        setData(d);

      })
      .catch( e => {
        // Error
      })
      
    })

    return InteractionManager.clearInteractionHandle(interaction);
  }, [])

  const openDocument = (ruta, nombre) => {
    setPopup({
      open: true,
      component: DocumentPopup,
      title: nombre,
      componentProps: {
        remove: () => { removeDocument(ruta) },
        download: () => { downloadDocument(ruta) }
      }
    })
  };

  const closePopup = () => {
    setPopup({open: false});
  }

  const removeDocument = (ruta) => {
    deleteDocument(user, refreshToken, ruta)
    .then( removed => {
      console.log(documents) // <--- Array []

      if( removed ){
        setDocuments(documents.filter( d => { return d.ruta !== ruta } ));
      }
      
      closePopup();
    })
    .catch( e => {
      // Error
      console.log(e);
    } )
  }

  const downloadDocument = (ruta) => {
    getDocument(user, refreshToken, ruta);
  }

  return (
    <KeyboardAvoidingView 
      behavior={Platform.OS == "ios" ? "padding" : "height"}
      style={[mainStyles.screenContainer, styles.mainView]}
      >
      <View style={styles.topSection}>
        <View style={styles.topInfo}>
          <Image 
            style={styles.image}
            source={require('../../../assets/default-person.png')}  
          />
          <View style={styles.nameView}>
            <Text 
              style={styles.name}
              numberOfLines={2}
              ellipsizeMode={'tail'}
            >{name}</Text>
            <View style={styles.location}>
              <HomeOutline 
                style={styles.homeIcon}
                stroke={'#121212'}
              />
              <Text style={styles.homeText}>Casa E | Habitación 3</Text>
            </View>
          </View>
        </View>
        <ButtonsRow
          buttons={buttons}
        />
      </View>
      <View style={styles.bottomSection}>
        <ScrollView style={styles.scroll} showsVerticalScrollIndicator={false}>
          { documents.length!=0 && 
            <ListTitle title={'Documentos'} />
          }
          { documents.length!=0 && 
            <DocumentList
              style={styles.documents}
              documents={documents}
            />
          }
          { data.length!=0 && 
            <View style={styles.datos}>
              <ListTitle title={'Datos'} />
              <DataList data={data} /> 
            </View>
          }
          { documents.length==0 && data.length==0 && 
            <ActivityIndicator style={styles.loading} size="large" color="#054956" />
          }
        </ScrollView>
      </View>
        { popup.open && <TouchableOpacity activeOpacity={0.6} style={mainStyles.outsidePopup} onPress={closePopup} /> }
        { popup.open && 
          <Popup
            title={popup.title}
            component={popup.component}
            componentProps={popup.componentProps}
          />
        }
    </KeyboardAvoidingView>
  );  

}

module.exports = PersonScreen;

1 个答案:

答案 0 :(得分:0)

我遵循了这个解决方案:

我不完全理解 React 在这种情况下是如何工作的,但我找到了一个使用 refs 的解决方案。我不知道为什么,但不修改状态,它并不总是最新的。为了确保我使用的是最后一个,我创建了一个指向 document 状态的最后一个版本的引用:

  {...}

  const [documents, setDocuments] = useState([]);
  const [data, setData] = useState([]);
  const [name, setName] = useState('');
  const [popup, setPopup] = useState({open: false});
  const docsRef = useRef();

  docsRef.current = documents;

现在,我不再使用函数内部的文档,而是使用 docsRef.current