3

I'm struggling to make use of an object in react, I'm trying to access the key:value that is being returned (and I can successfully console.log).

All the examples I've tried result in either mapping each character or throwing an object child error and i'm at a loss.

  componentDidMount() {
    this.gun.on('auth', () => this.thing());
  }

  thing() {
    this.gun.get('todos').map((value, key) => { console.log(key, value) }
    );
  }

  handleChange = e => this.setState({ newTodo: e.target.value })

  add = e => {
    e.preventDefault()
    this.gun.get('todos').set(this.state.newTodo)
    this.setState({ newTodo: '' })
  }

  del = key => this.gun.get(key).put(null)

  render() {
    return <>
      <Container>
        <div>Gun</div>
        <div>
          <form onSubmit={this.add}>
            <input value={this.state.newTodo} onChange={this.handleChange} />
            <button>Add</button>
          </form>
          <br />
          <ul>
            {this.state.todos.map(todo => <li key={todo.key} onClick={_ => this.del(todo.key)}>{todo.val}</li>)}
          </ul>
        </div>
      </Container></>
  }
}
jhizzle207
  • 65
  • 5

1 Answers1

1

There are a few ways to synchronize your components state with another data source (ie the gun object) - one simple approach would be to cache a copy of the todo data that you plan to render, in your component's state.

This is done via the setState() function which when called, causes the component to re-render. In the case of your component's render() method, changing the todos state field will updated list to display.

With this approach, you'd need to ensure that when you make changes to the gun object's todos data, you also update the components todo state via setState() as shown below:

constructor(props) {
    super(props)

    /* Setup inital state shape for component */
    this.state = {
        todos : [], 
        newTodo : ''
    }
}

mapTodos() {
    return this.gun.get('todos').map((value, key) => ({ key : key, val : value }));
}

componentDidMount() {
    this.gun.on('auth', () => this.mapTodos());
}

handleChange = e => this.setState({ newTodo: e.target.value })

add = e => {
    e.preventDefault()
    this.gun.get('todos').set(this.state.newTodo)

    /* When adding a todo, update the todos list of the component's internal state
    to cause a re-render. This also acts as a cache in this case to potentially speed
    up render() by avoiding calls to the gun.get() method */
    this.setState({ newTodo: '', todos : this.mapTodos() })
}

del = key => {
    this.gun.get(key).put(null)

    /* Call setState again to update the todos field of the component state to
    keep it in sync with the contents of the gun object */
    this.setState({ newTodo: '', todos : this.mapTodos() })
}

render() {
    return <Container>
        <div>Gun</div>
        <div>
            <form onSubmit={this.add}>
            <input value={this.state.newTodo} onChange={this.handleChange} />
            <button>Add</button>
            </form>
            <br />
            <ul>
            {this.state.todos.map(todo => <li key={todo.key} onClick={ () => this.del(todo.key) }>{todo.val}</li>)}
            </ul>
        </div>
    </Container>
}
Dacre Denny
  • 29,664
  • 5
  • 45
  • 65
  • mapTodo's isn't actually setting the data on this.state.todos, if I add that in it's undefined (I expect it to throw an object error but not sure why its undefined, the console log returns the correct data) – jhizzle207 Feb 20 '19 at 01:18
  • If I lose the () after `this.mapTodos` that resolves the undefined issue, but then we're back to the issue of it `.map` isn't a function on `this.state.todos` (presumably because its an object?) – jhizzle207 Feb 20 '19 at 01:25
  • @jhizzle207 my apologies, noticed I missed a `return` statement - just updated answer (see changes to `mapTodos()`). Does this help? – Dacre Denny Feb 20 '19 at 01:46
  • back to square one: `Error: Objects are not valid as a React child (found: object with keys {_}). If you meant to render a collection of children, use an array instead.` – jhizzle207 Feb 20 '19 at 03:07
  • @jhizzle207 made a small change to the `onClick` handler on your `
  • ` - any progress with that?
  • – Dacre Denny Feb 20 '19 at 03:32
  • No, the object issue remains. – jhizzle207 Feb 20 '19 at 06:15
  • Out of interest, what happens if you replace `{todo.val}` with `{JSON.stringify(todo)}` ? – Dacre Denny Feb 20 '19 at 07:35
  • Still get the objects error, so the page doesn't load to see what the output is... – jhizzle207 Feb 20 '19 at 17:29
  • Would you be able to upload your project to GitHub for me to have a look at it in full? – Dacre Denny Feb 20 '19 at 18:53