Ad

How To Get The State Of A React App?

- 1 answer

So, I've built up this React app with some state. I want to know what that state is, so I can save it to localStorage and let state carry from one session to another. Basically, the app is pretty complex and I don't want people to lose their "place" just because the closed it and opened it again later.

Reading through the React docs though, I don't see anything that references accessing a component's state from outside of React.

Is this possible?

Ad

Answer

You should never ever try to get a state from a component as a component should always be representing and not generate state on its own. Instead of asking for the component's state, ask for the state itself.

That being said, I definitely see where you're coming from. When talking about React, the term "state" seems to be pretty ambiguous indeed.

I don't see anything that references accessing a component's state from outside of React.

Once and for all, here's the difference:

  • Local state, shouldn't persist: this.state, this.setState et al. Local state lives only within the component and will die once the component dies.
  • Global state, can be persisted: this.props.passedState. Global state is only passed to the component, it can not directly modify it. The view layer will adjust to whatever global state it got passed.

Or in simple:

  • this.state means local state, won't get persisted.
  • this.props.state means passed state, could be persisted, we just don't know and we don't care.

Example

The following example uses stuff of Babel's stage-1 Preset

React is all about giving a display representation of a data structure. Let's assume we have the following object to visibly represent:

let fixtures = {
   people: [
        {
            name: "Lukas"
        },
        {
            name: "fnsjdnfksjdb"
        }
    ]
}

We have an App component in place, that renders Person components for every entry in the people array.

import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';

class Person extends Component {

    static propTypes = {
        name: PropTypes.string.isRequired
    }

    render() {
        return (
            <li>
                <input type="text" value={this.props.name} />
            </li>
        );
    }
}

class App extends Component {

    static propTypes = {
        people: PropTypes.array.isRequired
    }

    render() {
        let people = this.people.map(person => {
            <Person name={person.name} />
        });
        return (
            <ul>
                {people}
            </ul>
        );
    } 
}

ReactDOM.render(
    <App people={fixtures} />, 
    document.getElementById('yourid')
);

Now, we will implement focus functionality. There are 2 options:

  1. We don't care about which person was focused the last time the user used the app, so we use local state.
  2. We do care about which person was focused the last time the user used the app, so we use global state.

Option 1

The task is simple. Just adjust the People component so that it knows (and rerenders) once the focus changed. The original data structure won't be changed and the information whether a component is focused or not is merely client side information that will be lost once the client is closed/reset/whatever. State is local: We use component.setState to dispatch changes to local state

class Person extends Component {
    static propTypes = {
        name: PropTypes.string.isRequired
    }
    constructor(...args) {
        super(...args);
        this.state = {
            isFocused: false
        }
        this.onFocus = this.onFocus.bind(this);
        this.onBlur = this.onBlur.bind(this);
    }

    static propTypes = {
        name: PropTypes.string.isRequired
    }

    onFocus() {
        this.setState({
            isFocused: true;
        });
    }

    onBlur() {
        this.setState({
            isFocused: false;
        });
    }

    render() {
        let borderColor = this.state.isFocused ? '#ff0' : '#000'; 
            style = {
                border: `1px solid ${borderColor}`
            }
        return (
            <li>
                <input 
                    style={style} 
                    type="text" 
                    value={this.props.name} 
                    onFocus={this.onFocus}
                    onBlur={this.onBlur}
                    />
            </li>
        );
    }
}

Option 2

We actually want to persist the focused element to whatever store (eg. backend) we have, because we care about the last state. State is global: React components receive only props as "state", even granular information as whether an element is focused. Persist and feed global state to the app and it will behave accordingly.

function setFocus(index) {
    fixtures.people[index].isFocused = true;
    render();
}

function clearFocus(index) {
    fixtures.people[index].isFocused = false;
    render();
}

function render() {
    ReactDOM.render(
    <App people={fixtures} />, 
    document.getElementById('yourid')
    );
} 


class Person extends Component {
    static propTypes = {
        name: PropTypes.string.isRequired,
        isFocused: PropTypes.bool,
        index: PropTypes.number.isRequired
    }

    static defaultProps = {
        isFocused: false
    }

    constructor(...args) {
        super(...args);
        this.onFocus = this.onFocus.bind(this);
        this.onBlur = this.onBlur.bind(this);
    }

    static propTypes = {
        name: PropTypes.string.isRequired
    }

    onFocus() {
        setFocus(this.props.index);
    }

    onBlur() {
        clearFocus(this.props.index);
    }

    render() {
        let borderColor = this.props.isFocused ? '#ff0' : '#000'; 
            style = {
                border: `1px solid ${borderColor}`
            }
        return (
            <li>
                <input 
                    style={style} 
                    type="text" 
                    value={this.props.name} 
                    onFocus={this.onFocus}
                    onBlur={this.onBlur}
                    />
            </li>
        );
    }
}

class App extends Component {

    static propTypes = {
        people: PropTypes.array.isRequired
    }

    render() {
        let people = this.people.map((person, index) => {
            <Person name={person.name} index={index} isFocused={person.isFocused} />
        });
        return (
            <ul>
                {people}
            </ul>
        );
    } 
}
render();
Ad
source: stackoverflow.com
Ad