这有点乱,但我一直在尝试 - 字面意思 - 整天让我有点疲惫。
我正在尝试做一些在JQuery中花费我20秒的事情,但是在React中 _(ツ)_ /¯
基本上,在我的应用程序中,标签具有与之相关的重要性(1-9)。好东西。
我有一个列表组,按重要性顺序返回我的标记:
const TagScreen = ({
tags
}) =>
{
return(
<ListGroup>
{ tags.sort(function(a,b) {return a.importance < b.importance}).map((tag) =>
( <span key={tag.id}>
<ListGroupItem className='taglist' bsStyle="success"><p>{tag.name}</p>
<ListItem
active={tag.importance} />
</ListGroupItem>
</span>
)
)}
</ListGroup>
)
}
ListItem是一个(非常)命名不佳的组件(当我开始工作时会有如此多的重构),但它本质上是一个重要的选择器。它看起来像这样:
const ListItem = ({index, active}) =>
{
var rows = [];
for (var i = 1; i < 10; i++) {
var style = '';
if (active === i) { style = "active" }
rows.push(<li className={style}><a href='#'>{i}</a></li>)
}
return(
<ul className="pagination pull-right pagination-sm">
{ rows.map((row) => row)}
</ul>
)
}
再一次,我确定这很可怕,我是一个反应新手。基本上,我想要的只是在分页元素上的'主动'样式(从标签的当前重要性开始)更改为单击的一个。我已经尝试过这么多,这么做。我将处理服务器的实际ping操作并稍后更改标签的重要性,一旦我有了这个该死的样式来改变onClick。
感谢您的帮助。
答案 0 :(得分:1)
好吧,你需要确保你有一个状态来保存你的更改,所以你需要一个包含状态的容器组件,或者使用像redux这样的东西来处理容器道具的状态
之后你可以这样做
const RangeSelector = ({min, max, current, onSelected}) => {
let items = [];
for (let i = min; i < max; i++) {
items.push(<li className={i === current && 'active'} onClick={(...args) => onSelected(i, ...args)}>{i}</li>);
}
return <ul>{ items }</ul>;
};
const Tag = props => {
return <div>
<h2>{ props.title }<small> ({ props.importance })</small></h2>
<RangeSelector current={ props.importance } min={1} max={11} onSelected={ (...args) => props.onUpdate( props.id, ...args ) } />
</div>;
};
class TagContainer extends React.Component {
constructor(...args) {
super(...args);
this.state = {
tags: [
{ id: 0, title: 'C#', importance: 5 },
{ id: 1, title: 'JavaScript', importance: 1 }
] };
}
updateTag(id, value) {
this.setState( this.state.tags.reduce( (current, item) => {
if (item.id === id) {
item.importance = value;
}
current.push( item );
return current;
}, [] ) );
}
render() {
return <div>
<h1>Tags</h1>
<div className="tag-list">
{ this.state.tags.map( (tag, key) => <Tag onUpdate={(...args) => this.updateTag(...args)} key={tag.id} {...tag} /> ) }
</div>
</div>;
}
}
ReactDOM.render( <TagContainer />, document.querySelector('#app') );
.active { background-color: green; color: white; }
ul { list-style-type: none; display: inline-block; }
ul li { clear: none; display: inline-block; padding: 5px; }
ul li:hover { cursor: pointer; }
<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="app"></div>
所以上面的小应用程序的细节如下:
TagContainer
它将状态保存到标记,并在子组件发生更改时更新其状态。它以初始状态开始,您可以在构造函数中看到:
constructor(...args) {
super(...args);
this.state = {
tags: [
{ id: 0, title: 'C#', importance: 5 },
{ id: 1, title: 'JavaScript', importance: 1 }
] };
}
这意味着,我将有2个标签,一个使用C#,另一个使用JavaScript,重点分别为5和1
在渲染容器组件的过程中,它呈现一个名为Tag
的无状态组件,并在其道具上插入更新函数,您可以在此处看到:
<Tag onUpdate={(...args) => this.updateTag(...args)} key={tag.id} {...tag} />
这表明,当调用onUpdate
时,它会将更新转发给this.updateTag()
函数,该函数将更新状态。发送的所有参数也将转发给该函数。箭头函数确保this
的上下文引用当前的TagContainer实例。
通过this.setState()
函数更新状态,您可以在其中发送更新的状态,以便React可以重新呈现容器组件。
现在这可能看起来过于复杂了,它可能是,但它将在状态中重新创建tags数组,并更新一个要更改的状态
this.setState( this.state.tags.reduce( (current, item) => {
if (item.id === id) {
item.importance = value;
}
current.push( item );
return current;
}, [] ) );
id
和value
通过上面定义的2个无状态组件传入。
RangeSelector
和Tag
RangeSelector
仅负责显示特定范围内的可用值,并在当前选定的元素上设置活动类。点击它后,它会通过onSelected
组件1>}从它收到的Tag
方法发送值。
Tag
组件负责显示当前标记,并呈现标题和RangeSelector
。它从onUpdate
组件接收TagContainer
方法,当RangeSelector
调用它时,它会添加1个额外参数并将其转发到TagContainer
组件。
最后,状态发生了变化,并且react会重新渲染你的应用程序,从而导致DOM的更新(因为虚拟dom和真正的DOM之间存在差异)