Как передавать переменные при вызове компонентов

Я создаю мини-приложение и хочу сделать его чище. Итак, в основном я хочу иметь 3 компонента: App, List и Person.

Вот код: App.js

import React, { Component } from "react";
import List from './List';

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      results: [],
      search: '',
      currentPage: 1,
      todosPerPage: 3
    };
    this.handleClick = this.handleClick.bind(this);
  }

  componentWillMount() {
    this.fetchData();
  }

  fetchData = async () => {
    const response = await fetch(API);
    const json = await response.json();
    this.setState({ results: json.results });
  };

  handleClick(event) {
    this.setState({
      currentPage: Number(event.target.id)
    });
  }

  updateSearch(event) {
    this.setState({ search: event.target.value.substr(0, 20) });
  }

  render() {
    return (
      <List />
    );
  }
}

export default App;

List.js

import React, { Component } from 'react';
import Person from './Person';

class List extends Component {
    render() {
        const { results, currentPage, todosPerPage } = this.state;
    const indexOfLastTodo = currentPage * todosPerPage;
    const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
    const currentTodos = results.slice(indexOfFirstTodo, indexOfLastTodo).filter(item => {
      return item.name.toLowerCase().indexOf(this.state.search) !== -1;
    });

    const renderTodos = currentTodos.map((item, index) => {
      return (
        <Person item = {this.state.item} index = {this.state.index}/>
      );
    });

    const pageNumbers = [];
    for (let i = 1; i <= Math.ceil(results.length / todosPerPage); i++) {
      pageNumbers.push(i);
    }

    const renderPageNumbers = pageNumbers.map(number => {
      return (
        <li className = "page-link" key = {number} id = {number} onClick = {this.handleClick} style = {{cursor: "pointer"}}>{number}</li>
      );
    });

    return (
      <div className = "flex-grow-1">
        <h1>Personnages de Star Wars</h1>
        <form className = "mb-4">
          <div className = "form-group">
            <label>Rechercher</label>
            <input 
            className = "form-control" 
            type = "text"
            placeholder = "luke skywalker..."
            value = {this.state.search}
            onChange = {this.updateSearch.bind(this)}
            />
          </div>
        </form>
        <div className = "row mb-5">{renderTodos}</div>
        <nav aria-label = "Navigation">
          <ul id = "page-number" className = "pagination justify-content-center">{renderPageNumbers}</ul>
        </nav>
      </div>
    );
  }
}

export default List;

Person.js

import React, { Component } from 'react';

function Person(item, index) {
    return (
        <div className = "col-lg-4 mb-4" key = {index}>
      <div className = "card">
        <div className = "card-header">
          <h4 className = "mb-0">{item.name}</h4>
        </div>
        <div className = "card-body">
          <h5 className = "card-title">Caractéristiques</h5>
          <ul>
            <li>Année de naissance : {item.birth_year}</li>
            <li>Taille : {item.height} cm</li>
            <li>Masse : {item.mass}</li>
            <li>Couleur des yeux : {item.eye_color}</li>
            <li>Couleur de cheveux : {item.hair_color}</li>
            <li>Couleur de peau : {item.skin_color}</li>
          </ul>
          <a href = {item.url} className = "btn btn-primary">Sa fiche</a>
        </div>
      </div>
    </div>
    )
}

export default Person;

Моя проблема в том, что я получаю TypeError: Cannot read property 'results' of null при рендеринге.

Возможно ли, чтобы переменная попадала в каждый файл, если я определяю их все в App.js?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
0
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете использовать переменные передачи в реквизитах компонента <List />, передав состояние внутри функции рендеринга App.js при вызове <List /> следующим образом.

render() {
  //Passing Data inside props
  <List data = {this.state} />
}

и внутри вашего List.js вы можете получить доступ к переменной данных

const { results, currentPage, todosPerPage } = this.props.data;

Отлично, я понимаю эту часть! Как это работает с .map (внутри <List />)? Когда я позвоню <Person />const renderTodos = currentTodos.map((item, index) => { return ( <Person data = {this.state} /> ); }); и class Person extends Component { render() { const results = this.props.data; return ( <div className = "col-lg-4 mb-4" key = {results.index}> поймайте меня TypeError: Cannot read property 'index' of null

mttetc 06.04.2019 19:08

Вам нужно передать элемент внутри реквизита данных внутри компонента Person, и вам нужно передать индекс в качестве другого реквизита, подобного этому <Person data = {item} index = {index} />, и вы можете получить доступ к подобному индексу внутри компонента Person this.props.index, и вы можете получить доступ к данным the.props.data.

Rishabh Rawat 07.04.2019 11:30
Ответ принят как подходящий

Вы не правильно передаете данные. Попробуй это:

В App.js передайте компоненту List необходимые данные:

render() {
    return (
      <List data = {this.state}/>
    );
  }

Затем в методе render() в List.js получите переданную опору данных, а затем извлеките оттуда данные:

render() {
     const { data } = this.props;
     const { results, search, currentPage, todosPerPage } = data;
     // ...
     // in currentTodos function dont use this.state.search but just "search", that we got above from the data variable
     // ...
     // also your renderTodos should look like this - use the item and index variables
     const renderTodos = currentTodos.map((item, index) => {
      return (
        <Person item = {item} index = {index}/>
      );
    });

    // ...
}

Итак, ваш List.js должен выглядеть так:

import React, { Component } from 'react';
import Person from './Person';

class List extends Component {
    render() {
    // get the data
    const { data } = this.props;
    // get the properties
    const { results, search, currentPage, todosPerPage } = data;
    const indexOfLastTodo = currentPage * todosPerPage;
    const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
    const currentTodos = results.slice(indexOfFirstTodo, indexOfLastTodo).filter(item => {
      // use "search" variable
      return item.name.toLowerCase().indexOf(search) !== -1;
    });

    const renderTodos = currentTodos.map((item, index) => {
      return (
        // use item and index
        <Person item = {item} index = {index}/>
      );
    });

    const pageNumbers = [];
    for (let i = 1; i <= Math.ceil(results.length / todosPerPage); i++) {
      pageNumbers.push(i);
    }

    const renderPageNumbers = pageNumbers.map(number => {
      return (
        <li className = "page-link" key = {number} id = {number} onClick = {this.handleClick} style = {{cursor: "pointer"}}>{number}</li>
      );
    });

    return (
      <div className = "flex-grow-1">
        <h1>Personnages de Star Wars</h1>
        <form className = "mb-4">
          <div className = "form-group">
            <label>Rechercher</label>
            <input 
            className = "form-control" 
            type = "text"
            placeholder = "luke skywalker..."
            value = {search} // use search variable here too
            onChange = {this.updateSearch.bind(this)}
            />
          </div>
        </form>
        <div className = "row mb-5">{renderTodos}</div>
        <nav aria-label = "Navigation">
          <ul id = "page-number" className = "pagination justify-content-center">{renderPageNumbers}</ul>
        </nav>
      </div>
    );
  }
}

export default List;

И ваша функция в Person.js должна иметь следующее объявление, потому что параметры извлекаются из переданных реквизитов:

function Person({item, index}) {
     // ...
}

Другие вопросы по теме