2014-12-18 2 views
2

У меня есть ситуации, когда у меня есть два элемента, которые связаны друг с другом, с советом, который без negotiably всегда состоит из 4 уточняющих панелей:Как выбрать все дочерние компоненты (а не элементы DOM), используемые в шаблоне компонента Reactjs?

var BoardPanel = React.createClass({ 
    getInitialState: function() { 
    return { someval: '' }; 
    }, 
    render: function() { 
    <div>{this.state.someval}</div> 
    }, 
    doSomething: function(v) { 
    setState({ someval: v }); 
    } 
}); 

var BoardLayout = React.createClass({ 
    render: function() { 
    <div> 
     <h1>{this.props.label{</h1> 
     <div ref="panels"> 
     <BoardPanel /> 
     <BoardPanel /> 
     <BoardPanel /> 
     <BoardPanel /> 
     </div> 
    </div> 
    } 
}); 

BoardLayout должен быть в состоянии равномерно сказать каждое BoardPanel вызвать панель функции API, так что я хотел бы сделать React.js эквивалент:

this.querySelectorAll("BoardPanel") 
    .array() 
    .forEach(function(panel, idx) { 
     panel.doSomething(idx); 
    }); 

Обратите внимание, что я специально не хочу получить доступ к DOM узлов здесь, я хочу, чтобы получить доступ к React определенных виртуальным элементов, вызывать функции на этом и никогда не прикасаться фактический используемый DOM браузером.

Я имел взгляд на вспомогательные функции React.children, но это довольно бесполезно, потому что нет никакого способа, чтобы определить, какие дети, я хочу, и this.props.children собирается дать мне два div элементов, так как BoardPanel элементы живут " глубоко внутри шаблона.

(Я также не согласен с добавлением ref="..." с идентификаторами throwaway для каждого BoardPanel, потому что не должно быть необходимости это делать, учитывая, что это хорошо отформатированная структурированная разметка. Это возможное обходное решение, но кажется примерно так же разумно, как пощечины иды на каждом элементе в HTML-файл, вместо того, чтобы полагаться на селекторы запросов)

Я мог бы динамически генерировать их на самом деле не имея их в шаблоне вообще и добавить их с помощью React.create(BoardPanel) в BoardLayout.getInitialState, но это повлечет за сразу проницательную структуру шаблонов в непрозрачный местозаполнитель, что также я бы предпочел не делать.

Могу ли я, в BoardLayout.componentDidMount или как-нибудь получить массив из BoardPanel компонентов, чтобы я мог непосредственно проинструктировать эти компоненты, чтобы что-то делать? Если да, то как?

+0

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

+0

Если «BoardPanel» должен отреагировать на конкретные изменения, которые имеет смысл для него, он может проверять входящие реквизиты в ['componentWillReceiveProps'] (https://facebook.github.io/react/docs/component-specs. html # update-componentwillreceiveprops) и внести изменения внутри, прежде чем произойдет обновление. –

+0

они не просто реквизиты, хотя некоторые действия «на доске» требуют, чтобы каждая панель делала что-то свое, локальное для себя, похожее на простое JS, у вас был бы «boardlayout.querySelector (« boardpanel »). Array () .forEach (function (panel) {panel.reset();}); '(есть несколько вызовов, которые не принимают аргументов, поэтому для прокручивания это не имеет особого смысла, по крайней мере концептуально) –

ответ

4

Если вам нужно сделать это (вы, вероятно, нет), вам нужно использовать refs.

function refsToArray(ctx, prefix){ 
    var results = []; 
    for (var i=0;;i++){ 
    var ref = ctx.refs[prefix + '-' + String(i)]; 
    if (ref) results.push(ref); 
    else return results; 
    } 
} 

var BoardLayout = React.createClass({ 
    var makeRef = function(){ return 'BoardPanel-'+(_refi++); }, _refi=0; 
    render: function() { 
    <div> 
     <h1>{this.props.label{</h1> 
     <div ref="panels"> 
     <BoardPanel ref={makeRef()} /> 
     <BoardPanel ref={makeRef()} /> 
     <BoardPanel ref={makeRef()} /> 
     <BoardPanel ref={makeRef()} /> 
     </div> 
    </div> 
    } 
}); 

И тогда вы могли бы сделать, чтобы получить refsToArray(this, 'BoardPanel') массив рефов.

Но, как я уже сказал, вероятно, лучшее решение, но вы не указали, что вы на самом деле пытаетесь сделать.

+0

сообщение было в значительной степени тем, что я на самом деле пытаюсь сделать. У меня есть игровая панель с четырьмя панелями (это игра из четырех игроков), и в зависимости от действий «на игровом поле» все панели игроков должны выполнять одинаковые операции. Я использую refs atm, и это работает отлично, но также кажется, что я пишу слишком много кода для того, что должно быть доступно для обнаружения из самой структуры. –

+0

Похоже, вы должны использовать излучатель событий, передавая его компонентам BoardPanel в качестве опоры и позволяя им подписываться на различные события. – FakeRainBrigand

+0

Звучит как идеальное решение! Правда, это часть простого Реакта? Быстрый google показывает тонну примеров потока, которые я не использую. –