K. Li
K. Li

Reputation: 68

React - setting state

I am following along Samer Buna's Lynda course on "Full-Stack JavaScript Development: MongoDB, Node and React," and am wondering about a piece of code in the App component of the "Naming Contests" application. My questions is regarding the front-end React App component and in particular setting the state. The code block I'm having trouble figuring out is:

contests: {
          ...this.state.contests,
          [contest.id]: contest
        }

inside the fetchContest() function in the App component - App.js:

import React from 'react';
import Header from './Header';
import ContestList from './ContestList'; 
import Contest from './Contest';
import * as api from '../api';

const pushState =(obj, url) =>
  window.history.pushState(obj, '', url);

class App extends React.Component {
  static propTypes = {
    initialData: React.PropTypes.object.isRequired
  };
  state = this.props.initialData;
  componentDidMount() {}
  componentWillUnmount() {}
  fetchContest = (contestId) => {
    pushState(
      { currentContestId: contestId },
        `/contest/${contestId}`
      );
    api.fetchContest(contestId).then(contest => {
      this.setState({
        currentContestId: contest.id,
        contests: {
          ...this.state.contests,
          [contest.id]: contest
        }
      });
    });
    // lookup the contest
    // convert contests from array to object, for constant time lookup
    // this.state.contests[contestId]
  }
  pageHeader() {
    if (this.state.currentContestId) {
      return this.currentContest().contestName;
    }

    return 'Naming Contests';
  }
  currentContest() {
    return this.state.contests[this.state.currentContestId];
  }
  currentContent() {
    if (this.state.currentContestId) {
      return <Contest {...this.currentContest()} />;
    }

    return <ContestList 
        onContestClick={this.fetchContest}
        contests={this.state.contests} />;
  }
  render() {
    return (
    <div className="App">
      <Header message={this.pageHeader()} />
      {this.currentContent()}
    </div>
    );
  }
}

export default App;

api.js is the only file inside the 'api' directory, and it includes an axios call to retrieve a json object corresponding to each contest:

api.js:

import axios from 'axios';

export const fetchContest = (contestId) => {
  return axios.get(`/api/contests/${contestId}`)
              .then(resp => resp.data);
};

for reference, the json content of the contests look like this:

{
  "contests": [
    {
      "id": 1,
      "categoryName": "Business/Company",
      "contestName": "Cognitive Building Bricks"
    },
    {
      "id": 2,
      "categoryName": "Magazine/Newsletter",
      "contestName": "Educating people about sustainable food production"
    },
    {
      "id": 3,
      "categoryName": "Software Component",
      "contestName": "Big Data Analytics for Cash Circulation"
    },
    {
      "id": 4,
      "categoryName": "Website",
      "contestName": "Free programming books"
    }
  ]
}

I have seen the spread operator before, but I am unsure how it is used exactly in this context. Also, the '[contest.id]: contest' is confusing me as well. It'd be much appreciated if anyone could provide some clarification!

Upvotes: 0

Views: 146

Answers (1)

Simon Boudrias
Simon Boudrias

Reputation: 44589

So the spread operator will copy all the keys and values of one object into another. In the case of a Redux reducer, this is often used to clone the state and keep the store immutable.

[contest.id]: contest is computing a key. See Computed property keys.

For example, given contest.id is 34, and state.constests contains contest 32 and 33, you'll end up with an object looking like:

{
  '32': {}, // This is the same value as it was in the initial store
  '33': {}, // ... same here
  '34': contest // That's the new contest you want to inject in the store
}

Upvotes: 2

Related Questions