2

I have 2 arrays (array1 and array2) containing some words. The 2 arrays are looped and, at each iteration, a React component "Sentence" (with the props being a word from each array) is pushed to the state array "sentences". The first 5 elements of the array are displayed on browser.

var array1 = ["hello", "some", "words", "house", "garden", "car"];
var array2 = ["other", "bag", "of", "words", "oh", "yeah"];

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      sentences: []
    };
  }

  componentDidMount() {
    let sentences = this.state.sentences.slice();
    for (var i = 0; i < array1.length; i++) {
      for (var j = 0; j < array2.length; j++) {
        sentences.push(<Sentence word1={array1[i]} word2={array2[j]} />);
      }
    }
    this.setState({ sentences: sentences });
  }

  shuffle = () => {
    let temp = this.state.sentences.slice();

    for (let i = temp.length - 1; i > 0; i--) {
      let j = Math.floor(Math.random() * (i + 1));
      [temp[i], temp[j]] = [temp[j], temp[i]];
    }
    this.setState({ sentences: temp });
  };

  render() {
    return (
      <div>
        {this.state.sentences[0]}
        {this.state.sentences[1]}
        {this.state.sentences[2]}
        {this.state.sentences[3]}
        {this.state.sentences[4]}

        <Button variant="primary" onClick={this.shuffle}>
          Shuffle
        </Button>
      </div>
    );
  }
}

And Sentence.js

class Sentence extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      word1: this.props.word1,
      word2: this.props.word2
    };
  }

  render() {
    return (
      <div>
        First word: {this.state.word1}
        <br />
        Second word: {this.state.word2}
        <br />
        <br />
      </div>
    );
  }

}

The issue: when shuffling the array, the order of "sentences" shown in browser doesn't change.

(The shuffling algorithm is from this stackoverflow post)

Tom
  • 183
  • 1
  • 2
  • 9

1 Answers1

0

Try this code. I recommend you always try to use Components only inside of Component.render method and use Array.map for arrays inside render method instead of Referencing each children.

Hope this helps, have nice day!

const array1 = ["hello", "some", "words", "house", "garden", "car"];
const array2 = ["other", "bag", "of", "words", "oh", "yeah"];

class Sentence extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      word1: this.props.word1,
      word2: this.props.word2
    };
  }

  render() {
    return (
      <div>
        First word: {this.state.word1}
        <br />
        Second word: {this.state.word2}
        <br />
        <br />
      </div>
    );
  }
 }
 
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      sentences: []
    };
  }

  componentDidMount() {
    let sentences = this.state.sentences.slice();
    for (let i = 0; i < array1.length; i++) {
      for (let j = 0; j < array2.length; j++) {
        sentences.push({word1: array1[i], word2: array2[j], key: `sentence_i1${i}_j${j}`});
      }
    }
    this.setState({ sentences: sentences });
  }

  shuffle = () => {
    let temp = this.state.sentences.slice();

    for (let i = temp.length - 1; i > 0; i--) {
      let j = Math.floor(Math.random() * (i + 1));
      [temp[i], temp[j]] = [temp[j], temp[i]];
    }
    this.setState({ sentences: temp });
  };

  render() {
    return (
      <div>
        {this.state.sentences.map(props => <Sentence word1={props.word1} word2={props.word2} key={props.key} />)}

        <button variant="primary" onClick={this.shuffle}>
          Shuffle
        </button>
      </div>
    );
  }
}
    
ReactDOM.render(<App />, document.getElementById('app'));
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>React.js -- Shuffle demo</title>
</head>
<body>
  <div id="app"></div>
  <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
</body>
</html>
dalisoft
  • 172
  • 1
  • 11
  • This makes it work, thanks. Can you please clarify what do you mean by "use Components only inside of Component.render method" ? For example, my `this.state.sentences[0]` was inside the render method. Also, why did referencing each children not work? – Tom Feb 21 '19 at 22:08
  • I mean use use `` aka JSX only inside of `.render()` method, not in lifecycle methods or in functions. Referencing each children works, i just simplified syntax for code-style (just looks a little good), you can google Best practices for react.js (but don't use everything, learn what you need and what you like). Sorry for my bad english – dalisoft Feb 22 '19 at 14:20