Я по сути пытаюсь сделать вкладки в реакции, но с некоторыми проблемами.
Вот файл page.jsx
<RadioGroup>
<Button title="A" />
<Button title="B" />
</RadioGroup>
Когда вы нажимаете кнопку A, компонент RadioGroup должен отменить выбор кнопки B .
«Выбранный» означает просто className из состояния или собственности.
Вот RadioGroup.jsx
:
module.exports = React.createClass({
onChange: function( e ) {
// How to modify children properties here???
},
render: function() {
return (<div onChange={this.onChange}>
{this.props.children}
</div>);
}
});
Источник на Button.jsx
самом деле не имеет значения, у него есть обычный переключатель HTML, который запускает собственное onChange
событие DOM
Ожидаемый поток:
- Нажмите кнопку "A"
- Кнопка «A» запускает onChange, собственное событие DOM, которое всплывает в RadioGroup.
- RadioGroup onChange слушатель называется
- RadioGroup нужно отменить выбор кнопки B . Это мой вопрос.
Вот основная проблема, с которой я сталкиваюсь: я не могу перейти в <Button>
sRadioGroup
, потому что его структура такова, что дочерние элементы являются произвольными . То есть разметка могла быть
<RadioGroup>
<Button title="A" />
<Button title="B" />
</RadioGroup>
или же
<RadioGroup>
<OtherThing title="A" />
<OtherThing title="B" />
</RadioGroup>
Я пробовал несколько вещей.
Попытка: В RadioGroup
обработчик OnChange «s:
React.Children.forEach( this.props.children, function( child ) {
// Set the selected state of each child to be if the underlying <input>
// value matches the child's value
child.setState({ selected: child.props.value === e.target.value });
});
Проблема:
Invalid access to component property "setState" on exports at the top
level. See react-warning-descriptors . Use a static method
instead: <exports />.type.setState(...)
Попытка: В RadioGroup
обработчик OnChange «s:
React.Children.forEach( this.props.children, function( child ) {
child.props.selected = child.props.value === e.target.value;
});
Проблема: ничего не происходит, даже я даю Button
классу componentWillReceiveProps
метод
Попытка: я попытался передать определенное состояние родительского элемента дочерним элементам, поэтому я могу просто обновить родительское состояние и заставить детей отвечать автоматически. В функции рендеринга RadioGroup:
React.Children.forEach( this.props.children, function( item ) {
this.transferPropsTo( item );
}, this);
Проблема:
Failed to make request: Error: Invariant Violation: exports: You can't call
transferPropsTo() on a component that you don't own, exports. This usually
means you are calling transferPropsTo() on a component passed in as props
or children.
Плохое решение №1 : используйте метод response -addons.js cloneWithProps для клонирования дочерних элементов во время рендеринга, RadioGroup
чтобы иметь возможность передавать им свойства
Плохое решение №2 : реализовать абстракцию вокруг HTML / JSX, чтобы я мог передавать свойства динамически (убейте меня):
<RadioGroup items=[
{ type: Button, title: 'A' },
{ type: Button, title: 'B' }
]; />
А затем RadioGroup
динамически создавайте эти кнопки.
Этот вопрос мне не помогает, потому что мне нужно представить своих детей, не зная, что они из себя представляют.
RadioGroup
знать, что им нужно реагировать на событие своих произвольных потомков? Ему обязательно нужно что-то знать о своих детях.React.addons.cloneWithProps
и передавая новые свойства, которые вы хотели бы иметь.props
неизменяемы, поэтому вы создаете новый хеш, объединяете его с текущими реквизитами и передаете новый хешprops
новому экземпляру дочернего компонента.Ответы:
Я не уверен, почему вы говорите, что использование
cloneWithProps
- плохое решение, но вот рабочий пример его использования.var Hello = React.createClass({ render: function() { return <div>Hello {this.props.name}</div>; } }); var App = React.createClass({ render: function() { return ( <Group ref="buttonGroup"> <Button key={1} name="Component A"/> <Button key={2} name="Component B"/> <Button key={3} name="Component C"/> </Group> ); } }); var Group = React.createClass({ getInitialState: function() { return { selectedItem: null }; }, selectItem: function(item) { this.setState({ selectedItem: item }); }, render: function() { var selectedKey = (this.state.selectedItem && this.state.selectedItem.props.key) || null; var children = this.props.children.map(function(item, i) { var isSelected = item.props.key === selectedKey; return React.addons.cloneWithProps(item, { isSelected: isSelected, selectItem: this.selectItem, key: item.props.key }); }, this); return ( <div> <strong>Selected:</strong> {this.state.selectedItem ? this.state.selectedItem.props.name : 'None'} <hr/> {children} </div> ); } }); var Button = React.createClass({ handleClick: function() { this.props.selectItem(this); }, render: function() { var selected = this.props.isSelected; return ( <div onClick={this.handleClick} className={selected ? "selected" : ""} > {this.props.name} ({this.props.key}) {selected ? "<---" : ""} </div> ); } }); React.renderComponent(<App />, document.body);
Вот jsFiddle, показывающий это в действии.
EDIT : вот более полный пример с динамическим содержимым вкладки: jsFiddle
источник
this
. Есть ли какое-то реальное преимущество, кроме использования React?Кнопки не должны иметь состояния. Вместо того, чтобы явно обновлять свойства кнопки, просто обновите собственное состояние группы и выполните повторную визуализацию. Затем метод рендеринга группы должен смотреть на свое состояние при рендеринге кнопок и передавать «активный» (или что-то еще) только активной кнопке.
источник
Может быть, у меня странное решение, но почему бы не использовать шаблон наблюдателя?
module.exports = React.createClass({ buttonSetters: [], regSetter: function(v){ buttonSetters.push(v); }, handleChange: function(e) { // ... var name = e.target.name; //or name this.buttonSetters.forEach(function(v){ if(v.name != name) v.setState(false); }); }, render: function() { return ( <div> <Button title="A" regSetter={this.regSetter} onChange={handleChange}/> <Button title="B" regSetter={this.regSetter} onChange={handleChange} /> </div> ); });
module.exports = React.createClass({ onChange: function( e ) { // How to modify children properties here??? }, componentDidMount: function() { this.props.regSetter({name:this.props.title,setState:this.setState}); }, onChange:function() { this.props.onChange(); }, render: function() { return (<div onChange={this.onChange}> <input element .../> </div>); } });
возможно, вам нужно что-то еще, но я нашел это очень мощным,
Я действительно предпочитаю использовать внешнюю модель, которая предоставляет методы регистра наблюдателя для различных задач.
источник
Button.jsx
?onChange()
иonChange(e)
Создайте объект, который действует как посредник между родителем и потомком. Этот объект содержит ссылки на функции как в родительском, так и в дочернем. Затем объект передается как опора от родителя к потомку. Пример кода здесь:
https://stackoverflow.com/a/61674406/753632
источник