He leído esta publicación: Reaccionar setState no se actualiza inmediatamente

Y me di cuenta de que setState es asíncrono y puede requerir un segundo argumento como función para lidiar con el nuevo estado.

Ahora tengo una casilla de verificación

class CheckBox extends Component {
    constructor() {
        super();
        this.state = {
            isChecked: false,
            checkedList: []
        };
        this.handleChecked = this.handleChecked.bind(this);
    }

    handleChecked () {
        this.setState({isChecked: !this.state.isChecked}, this.props.handler(this.props.txt));
    }

    render () {
        return (
            <div>
                <input type="checkbox" onChange={this.handleChecked} />
                {`   ${this.props.txt}`}
            </div>
            )
    }
}

Y está siendo utilizado por otra aplicación

class AppList extends Component {
    constructor() {
        super();
        this.state = {
            checked: [],
            apps: []
        };
        this.handleChecked = this.handleChecked.bind(this);
        this.handleDeleteKey = this.handleDeleteKey.bind(this);
    }
    handleChecked(client_id) {
        if (!this.state.checked.includes(client_id)) {
            let new_apps = this.state.apps;
            if (new_apps.includes(client_id)) {
                new_apps = new_apps.filter(m => {
                    return (m !== client_id);
                });
            } else {
                new_apps.push(client_id);
            }
            console.log('new apps', new_apps);
            this.setState({apps: new_apps});
            // this.setState({checked: [...checked_key, client_id]});
            console.log(this.state);
        }
    }
    render () {
        const apps = this.props.apps.map((app) =>
            <CheckBox key={app.client_id} txt={app.client_id} handler={this.handleChecked}/>
        );

        return (
            <div>
                <h4>Client Key List:</h4>
                {this.props.apps.length > 0 ? <ul>{apps}</ul> : <p>No Key</p>}
            </div> 
        );
    }


}

Entonces, cada vez que cambia el estado de la casilla de verificación, actualizo el this.state.apps en AppList

Cuando console.log new_apps, todo funciona en consecuencia, pero console.log(this.state) muestra que el estado no se actualiza inmediatamente, lo que se espera. Lo que necesito saber es cómo puedo asegurarme de que el estado se actualice cuando necesito realizar más acciones (como registrar todas estas cadenas seleccionadas o algo así)

0
JChao 7 sep. 2018 a las 18:41

3 respuestas

La mejor respuesta

SetState le permite realizar una función de devolución de llamada después de establecer el estado para que pueda obtener el estado real

this.setState({stateYouWant}, () => console.log(this.state.stateYouWant))

En tu caso:

this.setState({apps: new_apps}, () => console.log(this.state))
5
Ricardo Costa 7 sep. 2018 a las 15:55

En realidad no debería haber dos estados que mantengan la misma cosa. En cambio, la casilla de verificación debe estar sin estado, el estado solo debe mantenerse en la Lista de aplicaciones y luego pasar:

const CheckBox = ({ text, checked, onChange }) => 
        (<span><input type="checkbox" checked={checked} onChange={() => onChange(text)} />{text}</span>);
        
class AppList extends React.Component {
  constructor() {
    super();
    this.state = { 
      apps: [
        {name: "One", checked: false },
        { name: "Two", checked: false }
      ], 
    };
  }
  
  onChange(app) {
    this.setState(
      previous => ({ 
         apps: previous.apps.map(({ name, checked }) => ({ name, checked: checked !== (name === app) })),
      }),
      () => console.log(this.state)
    );
  }
  
  render() {
    return <div>
     {this.state.apps.map(({ name, checked }) => (<CheckBox text={name} checked={checked} onChange={this.onChange.bind(this)} />))}
    </div>;
  }
}

ReactDOM.render(<AppList />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
2
Jonas Wilms 7 sep. 2018 a las 16:09

Los demás tienen la respuesta correcta con respecto a la devolución de llamada setState, pero también sugeriría que CheckBox no tenga estado y pase isChecked desde MyApp como accesorio. De esta manera, solo mantiene un registro de si el elemento está marcado y no necesita sincronizar entre los dos.

2
rooch84 7 sep. 2018 a las 15:49