在React

时间:2017-10-24 16:53:40

标签: javascript reactjs

这有点乱,但我一直在尝试 - 字面意思 - 整天让我有点疲惫。

我正在尝试做一些在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。

感谢您的帮助。

1 个答案:

答案 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>

所以上面的小应用程序的细节如下:

  • 1个容器组件,名为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;
}, [] ) );

idvalue通过上面定义的2个无状态组件传入。

  • 2个无状态组件,RangeSelectorTag

RangeSelector仅负责显示特定范围内的可用值,并在当前选定的元素上设置活动类。点击它后,它会通过onSelected组件}从它收到的Tag方法发送值。

Tag组件负责显示当前标记,并呈现标题和RangeSelector。它从onUpdate组件接收TagContainer方法,当RangeSelector调用它时,它会添加1个额外参数并将其转发到TagContainer组件。

最后,状态发生了变化,并且react会重新渲染你的应用程序,从而导致DOM的更新(因为虚拟dom和真正的DOM之间存在差异)