Передача данных между компонентами React

251
08 февраля 2020, 00:50

Есть две компоненты одного уровня, мне нужно передать значение которое было получено в компоненте NavigationBar в компоненту SearchLine

import React from 'react';
import NavigationBar from '../NavigationBar/NavigationBar';
import MainComponent from '../MainComponent/MainComponent';
class BaseComponent extends React.Component {
 render() {
    return(
        <>
            <NavigationBar />
            <MainComponent />
        </>
    );
  }
}
export default BaseComponent;

компонента SearchLine содержится в MainComponent

import React from 'react';
import { Route, Redirect, Switch } from 'react-router';
import SearchLine from '../MainComponent/SearchLine/SearchLine';
class MainComponent extends React.Component {
render() {
    return(
        <>
            <Switch>
                    <Route exact path="/all_songs/" component={SearchLine} />
                    <Route path="/">
                        <Redirect to="/all_songs/" />
                    </Route>
             </Switch> 
        </>
    );
  }
}
export default MainComponent;

вот компонента NavigationBar

import React from 'react';
import { Link } from 'react-router-dom';
import './NavigationBar.css';
class NavigationBar extends React.Component {
constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {artName: ''};
  }
  handleChange(e) {
    this.setState({artName: e.target.value});
  }
render() {
    const artistName = this.state.artistName;
    return(
        <div className="navBlock">
            <img src={require('./search-solid.svg')} width={17} height={17} className="navImage"/>
            <input 
                placeholder="Type in to Search..." 
                className="input-title" 
                value={artistName}
                onChange={this.handleChange}
            />
            <div className="navContainer">
                <ul>
                    <Link to="/all_songs">All Songs</Link>
                </ul>
            </div>
            <div className="container">
                <ul>
                    <Link to="/albums">Albums</Link>
                </ul>
            </div>
        </div>
    );
  }
}
export default NavigationBar;

Я не понимаю как мне правильно взять из NavigationBar значение, которое было введено в input, и передать его в SearchLine?

Answer 1

Без Redux можно пойти путем передачи значения через props. Добавить в стейт базового компонента переменную, куда будем сохранять значение, а также добавить метод, который будет записывать это значение. Передадим значение через пропсу в MainComponent, а метод записи значения передадим через пропсу в NavigationBar. Получим что-то вроде следующего кода:

class BaseComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { artName: '' }; // переменная, в которой будем хранить значение
    this.onChangeArtValue = this.onChangeArtValue.bind(this);
  }
  onChangeArtValue(value) {
    this.setState({ artName: value });
  }
  render() {
    return(
        <>
            <NavigationBar onChangeArtValue={this.onChangeArtValue} />
            <MainComponent artName={this.state.artName} />
        </>
    );
  }
}

Далее перейдем в компонента NavigationBar и испольуем переданный через props метод внутри ранее написанного handleChange метода:

handleChange(e) {
  this.props.onChangeArtValue(e.target.value); // вызвали метод переданный через пропсу
}

Теперь при изменении значения внутри инпута в NavigationBar компоненте, будет меняться значение в стейте BaseComponent компонента. Оно же при изменении будет пробрасываться в MainComponent компонент и вызывать ререндеринг. Осталось внести правки в сам MainComponent компонент. Нам нужно написать вспомогательный метод для Route, чтобы правильно передать пропсу в компонент:

class MainComponent extends React.Component {
  constructor(props) {
    super(props);
    this.renderSearchLine = this.renderSearchLine.bind(this);
  }
  renderSearchLine() {
    // возвращаем SearchLine с переданной пропсой 
    return (
      <SearchLine artName={this.props.artName} />
    );
  }
  render() {
    return(
      <>
        <Switch>
          <Route exact path="/all_songs/" component={this.renderSearchLine} />
          <Route path="/">
            <Redirect to="/all_songs/" />
          </Route>
        </Switch> 
      </>
    );
  }
}

Можно не выделять отдельный метод, но я сделал для наглядного понимания отдельный метод. После этого, внутри компонента SearchLine появится пропса artName, для этого будет достаточно обратиться в пропсы, для получения ее значения: this.props.artName. То есть, логика передачи через пропсы достаточно прямолинейна и ясна.

Если данный подход покажется слишком громоздким, то советую обратить внимание на одну очень полезную штуковину под названием Redux.

Answer 2

Тебе необходимо использовать подъем состояния (обратный поток данных).

Вот структура компонента BaseComponent:

import React from 'react'; 
 
import NavigationBar from '../NavigationBar/NavigationBar'; 
import MainComponent from '../MainComponent/MainComponent'; 
 
class BaseComponent extends React.Component { 
    state = { 
        yourStateName: null, 
    }; 
    lifting = (value) => 
        this.setState({yourStateName: value}); 
    render() { 
        return( 
            <> 
                <NavigationBar lifting={this.lifting.bind(this)} /> 
                <MainComponent yourAttributeName={this.state.yourStateName} /> 
            </> 
        ); 
    } 
} 
 
export default BaseComponent;

Здесь мы добавили состояние через упрощенный синтаксис yourNameState: null, создали функцию lifting, поднимающую состояние дочернего компонента NavigationBar, которую мы отправили ему же как свойство lifting, а также, добавили в MainComponent свойство yourAttributeName, в котором и будет содержаться необходимое ему состояние из NavigationBar, которое теперь уже будет храниться в BaseComponent в качестве state yourStateName.

А вот уже в компоненте NavigationBar нужно правильно применить функцию lifting в функцию-обработчик события onChange элемента input.

Вот структура компонента NavigationBar:

import React from 'react'; 
import { Link } from 'react-router-dom'; 
 
import './NavigationBar.css'; 
 
class NavigationBar extends React.Component { 
     
    constructor(props) { 
        super(props); 
        this.handleChange = this.handleChange.bind(this); 
        this.state = {artName: ''}; 
    } 
    lifting = this.props.lifting; //Michael Pecker: добавляем классу метод lifting, значение берем из this.props 
    handleChange(e) { 
        this.setState({artName: e.target.value}); 
        this.lifting(e.target.value); //Michael Pecker: используем функцию lifting, чтобы отправить состояние родителю 
    } 
     
    render() { 
        const artistName = this.state.artistName; 
        return( 
            <div className="navBlock"> 
                <img src={require('./search-solid.svg')} width={17} height={17} className="navImage"/> 
                <input 
                    placeholder="Type in to Search..." 
                    className="input-title" 
 
                    value={artistName} 
                    onChange={this.handleChange} 
                /> 
 
                <div className="navContainer"> 
                    <ul> 
                        <Link to="/all_songs">All Songs</Link> 
                    </ul> 
                </div> 
                <div className="container"> 
                    <ul> 
                        <Link to="/albums">Albums</Link> 
                    </ul> 
                </div> 
            </div> 
        ); 
    } 
} 
 
export default NavigationBar;

READ ALSO
Как достать значение из JSON

Как достать значение из JSON

Нужно достать вот эти msgПытался через точку получить и через квадратные скобки, ничего не получается

245
css анимация и three.js

css анимация и three.js

На странице используется графика построенная с использованием threejs, пока графика строится хотел использовать прелоадер на css (крутилка, вертелка)

266
Как выполнить JavaScript через определенное время?

Как выполнить JavaScript через определенное время?

Нужно через 5 секунд после загрузки страницы выполнить javascript файл, который находиться на удаленном сервере, и доступен по ссылке:

261