2016-11-04 3 views
0

У меня есть два компонента, родитель и ребенок, как так:Проходит «этот» контекст через опоры анти-шаблон?

class Parent extends React.Component { 
    shuffle() { 
     ... 
    } 
    blur() { 
     ... 
    } 
    next() { 
     ... 
    } 
    previous() { 
     ... 
    } 
    render() { 
     return (
      <Child Parent={this} /> 
     ); 
    } 
} 

class Child extends React.Component { 
    constructor(props) { 
     super(); 

     this.state = {}; 

     this._onShuffleClick = this._onShuffleClick.bind(props.Parent); 
     this._onPreviousClick = this._onPreviousClick.bind(props.Parent); 
     this._onNextClick = this._onNextClick.bind(props.Parent); 
    } 
    _onShuffleClick(event) { 
     event.preventDefault(); 

     this.shuffled ? this.shuffle(false) : this.shuffle(true); // I can call parents method here as the 'this' context is the 'Parent'. 
     this.blur(event.target); 
     this.setState({test "test"}); //I can set the parents state here 
    } 
    _onPreviousClick(event) { 
     event.preventDefault(); 

     this.previous(); 
     this.blur(event.target); 
    } 
    _onNextClick(event) { 
     event.preventDefault(); 

     this.next(); 
     this.blur(event.target); 
    } 
    render() { 
     return (
      <a className="shuffle" key={1} onClick={this._shuffleOnClick}>{this.props.Parent.props.html.shuffle}</a>, 
      <a className="previous" key={2} onClick={this._previousOnClick}>{this.props.Parent.props.html.previous}</a>, 
      <a className="next" key={3} onClick={this._nextOnClick}>{this.props.Parent.props.html.next}</a>, 
     ); 
    } 
} 

Проходит контекст («это» ключевое слово) в качестве опоры анти-паттерн? Устанавливает состояние родителя у ребенка плохо?

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

+0

Этот вопрос ** не ** в основном основан на мнениях. То, что является или не является анти-паттерном, обычно не является субъективным. Тот, кто проголосовал за это, может захотеть отозвать свой голос. Только мои 2 цента. – Chris

+0

Реакт говорит, что реквизит должен быть неизменным и сверху вниз. компоненты не могут изменить свои собственные реквизиты. Это анти-шаблон, и я не думаю, что изменение реквизита в дочернем будет показывать влияние на родителя. – vijay

ответ

2

Вы можете взаимодействовать с родителем state дочерний компонент, но, вероятно, не так, как вы пытаетесь достичь этого.

Если вы хотите отправить во всех props родителя вниз к ребенку, вы можете сделать:

<Child {...this.props} /> 

Таким образом, вам не нужно указывать каждый отдельный prop по одному; вместо этого вы просто отправляете их всех. Ознакомьтесь с оператором с разбрасыванием here и here для получения дополнительной информации.Более подробная информация также на MDN:

Разброса синтаксис позволяет выражение раскладывается в тех местах, где несколько аргументов (для вызовов функциев) или несколько элементов (для массива литералов) или нескольких переменных (для уничтожения того назначения), как ожидается.


Если вы хотите получить доступ или изменить state родителя от ребенка, вы должны сделать это немного по-другому. Как правило, вы должны создать функцию, которая выполняет это взаимодействие с state в вашем родителе, а затем отправить эту функцию как prop до ребенка. Как это:

Родитель:

_modifyState = (bar) => { 
    this.setState({foo: bar}); 
} 
..... 
<Child modifyState={this._modifyState} /> 

Ребенок:

this.props.modifyState("Hello world!"); 

выше будет установлен state.foo в родительском к строке Hello world! от компонента ребенка.

Если вы хотите получить доступ ко всем переменным state, вы можете отправить его в виде prop ребенку (всему объекту), а затем выполнить функцию (например, выше), которая изменяет все состояние (не только одно свойство) - зависит от того, что вы хотите на самом деле.

+0

Можно ли использовать '{... this.props}', даже если когда ребенок не использовать все родительские реквизиты? То есть избыточные свойства отправляются –

+0

@MartinMazzaDawson, да, это прекрасно. Вы все равно передаете ссылку, так что это не имеет большого значения ... если вы все еще чувствуете, что это избыточно, вы можете отбросить реквизит, который, как вы знаете, вам не нужны * до * вы отправляете в реквизиты. Я затронул вопрос [здесь] (http://stackoverflow.com/a/40280490/2030321) - хотя это другой вопрос, вы можете увидеть, как изменить реквизит перед его отправкой (с мелкой копией, а затем удалить '). – Chris

0

Примечание: Я не эксперт и не начинаю начинать, рассматривайте это скорее как мнение, чем руководство.

Я думаю, да, потому что вы вынуждаете особую реализацию. Что бы вы сделали, если бы хотели использовать эти методы в GrandParent? Если вы используете реквизит, эта модификация очень проста, но с вашей реализацией это будет боль в заднице.

Существует также функция, называемая PropTypes. Это действительно здорово сделать компоненты многоразовыми, но это еще одна вещь, которую вы не можете использовать, если делаете то, что вы предлагали.

Возможно, это только я, но это также создает большое замешательство. Вы должны передать все необходимое, как реквизит.

установка также родительское состояния как этот

this.setState({test "test"}); //I can set the parents state here 

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

1

Ну, это в основном плохое использование проходов вокруг реквизита, вы также можете пойти за {...props}, и я не хочу передавать его через полное имя, вы также можете использовать let { props } = this; let parentProps = props.Parent.props. Вопрос также в том, почему вы ссылаетесь на родительские реквизиты, которые кажутся плохой практикой, делятся и согласуются, только передают реквизиты, которые действительно необходимы, и не предполагают в ваших дочерних компонентах, что имеется определенный родительский компонент.

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

var StyledButton = React.createClass({ 
 
    propTypes: { 
 
    \t clickHandler: React.PropTypes.func.Required, 
 
    text: React.PropTypes.string.required 
 
    }, 
 
    render: function() { 
 
    let { clickHandler, text } = this.props; 
 
    return <button type="button" onClick={clickHandler}>{text}</button>; 
 
    } 
 
}); 
 

 
var MyForm = React.createClass({ 
 
\t click: function() { 
 
    \t alert('ouch'); 
 
    }, 
 
\t render: function() { 
 
    \t return <fieldset> 
 
    \t <StyledButton clickHandler={this.click} text="Click me" /> 
 
    </fieldset> 
 
    } 
 
}) 
 

 
ReactDOM.render(
 
    <MyForm />, 
 
    document.getElementById('container') 
 
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<div id="container"> 
 
    <!-- This element's contents will be replaced with your component. --> 
 
</div>

1

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

Когда ваша реализация родителя изменяется, дочерние компоненты будут разбиты из-за this.props.Parent.props.html.previous}.

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

class Parent extends React.Component { 

    doSomethingBeacauseTheChildStateHasChanged() { 
     // function 
    } 

    render() { 
     <Child doSomething={doSomethingBeacauseTheChildStateHasChanged.bind(this)}/> 
    } 
} 

class Child extends React.Component { 

    render() { 
     <button onClick={this.props.doSomething}>Child button</button> 
    } 

}

0

Вы можете вызвать функцию в родительском. Это правильный способ общения с родителем.

class Parent extends React.Component { 
    shuffle(e) { 
    console.log(e.target); 
    return false; 
    } 
    render() { 
    return (
     <Child onShuffle={this.shuffle} /> 
    ); 
    } 
} 

class Child extends React.Component { 
    render() { 
    return(
     <a href='#' onClick={this.props.onShuffle}>Shuffle</a> 
    ); 
    } 
} 
Child.propTypes = { 
    onShuffle: React.PropTypes.func 
} 
Смежные вопросы