Изменить свойства / состояние родительского компонента с дочернего

В настоящее время я изучаю REACT для создания веб-приложений. В этом приложении у меня есть список selectedCharacters в родительском состоянии, и в каждом дочернем компоненте у меня есть ввод для имени игрока. Я изо всех сил пытаюсь обновить имя игрока в родительском состоянии.

class Game extends React.Component {
  state = {
    selectedCharacters: [{"name":"Loup Garou","imgName":"base_loup.png","uniqueKey":"loup","playerName":""},{"uniqueKey":"voyante","imgName":"base_voyante.png","name":"Voyante","maxInGame":1,"left":1}]
  };
  changePlayerName = (char, newName) => {
    char.playerName = newName;
  };
  render() {
    const { selectedCharacters } = this.state;
    return(<CharactersSelection selectedCharacters={selectedCharacters} />);  
  }
}

const CharactersSelection = props => {
  return (
    <div className="row col-12 char-list">      
      <div className="col-md-9 col-xl-10 char-selected pad-r-10 pad-l-10">
        <div className="row char-selected-content">
          {props.selectedCharacters.map((char, i) => (
            <CharacterCardSelected key={i} imgName={char.imgName} name={char.name} playerName={char.playerName}/>
          ))}
        </div>
      </div>
    </div>
  );
};

const CharacterCardSelected = props => {
  return (
    <div className="d-flex char-card-selected" id={props.id}>
      <img alt={props.imgName} className="char-img-sm" src=require("../../public/images/" + props.imgName)}/>
      <div className="char-card-selected-txt">
        <div>
          <input
            type="text"
            className="form-control player-name"
            placeholder="Nom joueur..."
            value={props.playerName}
            onChange={e => {console.log(e)}}
          />
        </div>
      </div>
    </div>
  );
};

Помощь будет оценена.


person AnthonyDa    schedule 09.08.2018    source источник


Ответы (4)


Что вы сделаете, так это передадите функцию changePlayerName в качестве опоры в CharactersSelection, а оттуда передайте ее компоненту CharacterCardSelected. Теперь onChange CharacterCardSelected вызовите метод this.props.changePlayerName (name);

class Game extends React.Component {
  state = {
    selectedCharacters: [{"name":"Loup Garou","imgName":"base_loup.png","uniqueKey":"loup","playerName":""},{"uniqueKey":"voyante","imgName":"base_voyante.png","name":"Voyante","maxInGame":1,"left":1}]
  };
  changePlayerName = (char, newName) => {
    char.playerName = newName;
  };
  render() {
    const { selectedCharacters } = this.state;
    return(<CharactersSelection selectedCharacters={selectedCharacters} onChange={this.changePlayerName} />);  
  }
}

const CharactersSelection = props => {
  return (
    <div className="row col-12 char-list">      
      <div className="col-md-9 col-xl-10 char-selected pad-r-10 pad-l-10">
        <div className="row char-selected-content">
          {props.selectedCharacters.map((char, i) => (
            <CharacterCardSelected key={i} imgName={char.imgName} name={char.name} playerName={char.playerName} onChange={(newName) => {props.onChange(char,newName)}}/>
          ))}
        </div>
      </div>
    </div>
  );
};

const CharacterCardSelected = props => {
  return (
    <div className="d-flex char-card-selected" id={props.id}>
      <img alt={props.imgName} className="char-img-sm" src=require("../../public/images/" + props.imgName)}/>
      <div className="char-card-selected-txt">
        <div>
          <input
            type="text"
            className="form-control player-name"
            placeholder="Nom joueur..."
            value={props.playerName}
            onChange={e => {
              console.log(e);
              props.onChange(e.target.value)
            }}
          />
        </div>
      </div>
    </div>
  );
}; 
person samee    schedule 09.08.2018
comment
Хорошая идея, но когда я это делаю, я не могу ничего вводить во входные данные. Думаю мероприятие отменяется или что-то в этом роде - person AnthonyDa; 09.08.2018
comment
в этом случае удалите value={props.playerName} из <input .... , чтобы сделать его неконтролируемым компонентом. Если вы хотите присвоить какое-то значение по умолчанию, используйте атрибут defaultValue="". например <input defaultValue={props.playerName} remaining atrbs... /> - person samee; 09.08.2018

Расширяя ответ Майкла:

class Parent extends React.Component {
  state = { someValue: "" }

  onChangeValue = (event) => {
    this.setState({ someValue: event.target.value })
  }

  render () {
    const { someValue } = this.state
    return (
      <Child onChangeValue={this.onChangeValue} value{someValue}/>
    )
  }
}

class Child extends React.Component {
  render() {
    return (
      <input 
        onChange={this.props.onChangeValue} 
        value={this.props.value}
      />
    )
  }
}

Это распространенный шаблон в React, который называется подъем состояния.

person Tyler Sebastian    schedule 09.08.2018
comment
Мне нужно обновить имя в связанном символе в списке состояний selectedCharacters, нужно ли мне динамически создавать одну переменную состояния по символам? - person AnthonyDa; 09.08.2018
comment
Нет, просто измените onChangeValue, чтобы он принял идентификатор / имя / что-то, и измените соответствующий state.selectedCharacters элемент - person Tyler Sebastian; 09.08.2018
comment
см. ответ @samee - person Tyler Sebastian; 09.08.2018

Попробуйте создать функцию в родительском компоненте, а затем передать ее дочернему компоненту. Присвойте имя переменной состояния в родительском компоненте и передайте его дочернему компоненту.

person Michael    schedule 09.08.2018

Передайте функцию changePlayerName младшему дочернему элементу. Оттуда вам нужно вызвать setState родительского компонента, чтобы изменить имя игрока.

class Game extends React.Component {
        constructor(props) {
          super(props);
          this.state = {
            selectedCharacters: [{
              "name": "LoupGarou",
              "imgName": "base_loup.png",
              "uniqueKey": "loup",
              "playerName": ""
            }, {
              "uniqueKey": "voyante",
              "imgName": "base_voyante.png",
              "name": "Voyante",
              "maxInGame": 1,
              "left": 1
            }]
          }
        }
        changePlayerName = (index, newName) => {
          this.setState({
            selectedCharacters[index].playerName: newName
          });
        };
        render() {
          const {
            selectedCharacters
          } = this.state;
          return ( < CharactersSelection selectedCharacters = {
              selectedCharacters
            }
            changePlayerName = {
              this.changePlayerName
            }
            />);
          }
        }
        const CharactersSelection = props => {
            return ( < div className = "row col-12 char-list" > < div className =
                "col-md-9 col-xl-10 char-selected pad-r-10 pad-l-10" > < div className =
                "row char-selected-content" > {
                  props.selectedCharacters.map((char, index) => ( <
                      CharacterCardSelected key = {
                        index
                      }
                      imgName = {
                        char.imgName
                      }
                      changePlayerName = {
                        props.changePlayerName
                      }
                      name = {
                        char.name
                      }
                      playerName = {
                        char.playerName
                      }
                      />))
                    } < /div> < /div > < /div>);
                  };
                  const CharacterCardSelected = props => {
                    return ( < div className = "d-flex char-card-selected"
                      id = {
                        props.id
                      } > < img alt = {
                        props.imgName
                      }
                      className = "char-img-sm"
                      src = require("../../public/images/" + props.imgName)
                    }
                    /> < div className = "char-card-selected-txt" > < div > < input
                    type = "text"
                    className = "form-control player-name"
                    placeholder = "Nom joueur..."
                    value = {
                      props.playerName
                    }
                    onChange = {
                      (e) => props.changePlayerName(props.key, e.target.value)
                    }
                    /> < /div > < /div> < /div > );
                };
person Kosalram Rama Krishnan    schedule 09.08.2018