React js - 材质 ui - 传输列表 - 使用旧状态

Posted

技术标签:

【中文标题】React js - 材质 ui - 传输列表 - 使用旧状态【英文标题】:React js - material ui - transfer list -- using old states 【发布时间】:2021-02-04 04:01:00 【问题描述】:

我正在制作一个反应应用程序并尝试在材料 ui 上重新创建此传输列表演示 - 使用旧的状态方法。但是我掉进了一些陷阱。

当前沙箱 https://codesandbox.io/s/morning-voice-qrym9?file=/src/TransferList.js

https://material-ui.com/components/transfer-list/ - 基于简单列表 - 我正在尝试将其重新创建为组件 - 遵循其余组件的构建方式 - 但函数和状态声明中的内容是造成错误的连锁反应

我当前的代码。

import React,  Component  from 'react'
import  withRouter  from 'react-router-dom';
import  connect  from 'react-redux';
import  bindActionCreators  from 'redux';


import Grid from '@material-ui/core/Grid';
import List from '@material-ui/core/List';
import Card from '@material-ui/core/Card';
import CardHeader from '@material-ui/core/CardHeader';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import Checkbox from '@material-ui/core/Checkbox';
import Button from '@material-ui/core/Button';
import Divider from '@material-ui/core/Divider';


import './TransferList.scss';

class TransferList extends Component 
  
  constructor(props, context) 
    super(props, context);
    this.state = 
      checked: [],
      left: [0, 1, 2, 3],
      right: [4, 5, 6, 7]
    ;
  


  not(a, b) 
    //return a.filter((value) => b.indexOf(value) === -1);
  

  intersection(a, b) 
    //return a.filter((value) => b.indexOf(value) !== -1);
  

  union(a, b) 
    //return [...a, ...this.not(b, a)];
  



  numberOfChecked(items) 
    //return this.intersection(this.state.checked, items).length;
  

  handleToggleAll(items) 
    if (this.numberOfChecked(items) === items.length) 

      this.state = 
        checked: this.not(this.state.checked, items),
      ;
     else 

      this.state = 
        checked: this.union(this.state.checked, items),
      ;
    
  ;
  
  handleCheckedRight() 
   const leftChecked = this.intersection(this.state.checked, this.state.left);
    this.state = 
      right: this.state.right.concat(leftChecked),
      left: this.not(this.state.left, leftChecked),
      checked: this.not(this.state.checked, leftChecked),
    ;
  ;

  handleCheckedLeft() 
   const rightChecked = this.intersection(this.state.checked, this.state.right);

    this.state = 
      right: this.not(this.state.right, rightChecked),
      left: this.state.left.concat(rightChecked),
      checked: this.not(this.state.checked, rightChecked),
    ;
  ;

 customList(title, items) 
  return (
      <Card>
        <CardHeader
          //className=classes.cardHeader
          avatar=
            <Checkbox
              onClick=this.handleToggleAll(items)
              checked=this.numberOfChecked(items) === items.length && items.length !== 0
              indeterminate=this.numberOfChecked(items) !== items.length && this.numberOfChecked(items) !== 0
              disabled=items.length === 0
              inputProps= 'aria-label': 'all items selected' 
            />
          
          title=title
          subheader=`$this.numberOfChecked(items)/$items.length selected`
        />
        <Divider />
        <List 
          //className=classes.list 
          dense 
          component="div" 
          role="list"
        >
          
          <ListItem />
        </List>
      </Card>
    );
 



  render() 



    const leftChecked = this.intersection(this.state.checked, this.state.left);
    const rightChecked = this.intersection(this.state.checked, this.state.right);
/*
    const handleToggle = (value) => () => 
      const currentIndex = checked.indexOf(value);
      const newChecked = [...checked];

      if (currentIndex === -1) 
        newChecked.push(value);
       else 
        newChecked.splice(currentIndex, 1);
      

      setChecked(newChecked);
    ;

    const numberOfChecked = (items) => this.intersection(checked, items).length;

    const handleToggleAll = (items) => () => 
      if (numberOfChecked(items) === items.length) 
        setChecked(not(checked, items));
       else 
        setChecked(union(checked, items));
      
    ;

    const handleCheckedRight = () => 
      setRight(right.concat(leftChecked));
      setLeft(not(left, leftChecked));
      setChecked(not(checked, leftChecked));
    ;

    const handleCheckedLeft = () => 
      setLeft(left.concat(rightChecked));
      setRight(not(right, rightChecked));
      setChecked(not(checked, rightChecked));
    ;

    const customList = (title, items) => (
      <Card>
        <CardHeader
          className=classes.cardHeader
          avatar=
            <Checkbox
              onClick=handleToggleAll(items)
              checked=numberOfChecked(items) === items.length && items.length !== 0
              indeterminate=numberOfChecked(items) !== items.length && numberOfChecked(items) !== 0
              disabled=items.length === 0
              inputProps= 'aria-label': 'all items selected' 
            />
          
          title=title
          subheader=`$numberOfChecked(items)/$items.length selected`
        />
        <Divider />
        <List className=classes.list dense component="div" role="list">
          items.map((value) => 
            const labelId = `transfer-list-all-item-$value-label`;

            return (
              <ListItem key=value role="listitem" button onClick=handleToggle(value)>
                <ListItemIcon>
                  <Checkbox
                    checked=checked.indexOf(value) !== -1
                    tabIndex=-1
                    disableRipple
                    inputProps= 'aria-labelledby': labelId 
                  />
                </ListItemIcon>
                <ListItemText id=labelId primary=`List item $value + 1` />
              </ListItem>
            );
          )
          <ListItem />
        </List>
      </Card>
    );

*/


    return (
      <Grid container spacing=2 justify="center" alignItems="center">
        <Grid item>this.customList('Choices', this.state.left)</Grid>
        <Grid item>
          <Grid container direction="column" alignItems="center">
            <Button
              variant="outlined"
              size="small"
              //className=classes.button
              onClick=this.handleCheckedRight
              disabled=leftChecked.length === 0
              aria-label="move selected right"
            >
              &gt;
            </Button>
            <Button
              variant="outlined"
              size="small"
              //className=classes.button
              onClick=this.handleCheckedLeft
              disabled=rightChecked.length === 0
              aria-label="move selected left"
            >
              &lt;
            </Button>
          </Grid>
        </Grid>
        <Grid item>this.customList('Chosen', this.state.right)</Grid>
      </Grid>
    )
  



function mapStateToProps(state) 
  return 
  ;


function mapDispatchToProps(dispatch) 
 return bindActionCreators(  , dispatch);


export default withRouter(connect(mapStateToProps, mapDispatchToProps)(TransferList))



////////

/*

export default function TransferList() 
  const classes = useStyles();
  const [checked, setChecked] = React.useState([]);
  const [left, setLeft] = React.useState([0, 1, 2, 3]);
  const [right, setRight] = React.useState([4, 5, 6, 7]);

  const leftChecked = intersection(checked, left);
  const rightChecked = intersection(checked, right);

  const handleToggle = (value) => () => 
    const currentIndex = checked.indexOf(value);
    const newChecked = [...checked];

    if (currentIndex === -1) 
      newChecked.push(value);
     else 
      newChecked.splice(currentIndex, 1);
    

    setChecked(newChecked);
  ;

  const numberOfChecked = (items) => intersection(checked, items).length;

  const handleToggleAll = (items) => () => 
    if (numberOfChecked(items) === items.length) 
      setChecked(not(checked, items));
     else 
      setChecked(union(checked, items));
    
  ;

  const handleCheckedRight = () => 
    setRight(right.concat(leftChecked));
    setLeft(not(left, leftChecked));
    setChecked(not(checked, leftChecked));
  ;

  const handleCheckedLeft = () => 
    setLeft(left.concat(rightChecked));
    setRight(not(right, rightChecked));
    setChecked(not(checked, rightChecked));
  ;

  const customList = (title, items) => (
    <Card>
      <CardHeader
        className=classes.cardHeader
        avatar=
          <Checkbox
            onClick=handleToggleAll(items)
            checked=numberOfChecked(items) === items.length && items.length !== 0
            indeterminate=numberOfChecked(items) !== items.length && numberOfChecked(items) !== 0
            disabled=items.length === 0
            inputProps= 'aria-label': 'all items selected' 
          />
        
        title=title
        subheader=`$numberOfChecked(items)/$items.length selected`
      />
      <Divider />
      <List className=classes.list dense component="div" role="list">
        items.map((value) => 
          const labelId = `transfer-list-all-item-$value-label`;

          return (
            <ListItem key=value role="listitem" button onClick=handleToggle(value)>
              <ListItemIcon>
                <Checkbox
                  checked=checked.indexOf(value) !== -1
                  tabIndex=-1
                  disableRipple
                  inputProps= 'aria-labelledby': labelId 
                />
              </ListItemIcon>
              <ListItemText id=labelId primary=`List item $value + 1` />
            </ListItem>
          );
        )
        <ListItem />
      </List>
    </Card>
  );


*/

//////////

最新的沙盒工作 https://codesandbox.io/s/morning-voice-qrym9?file=/src/TransferList.js

【问题讨论】:

【参考方案1】:

可能不是完整的答案,而是在 customList() 中:

onClick=this.handleToggleAll(items)

调用方法而不是将其设置为事件处理程序,您可能想要:

onClick=() => this.handleToggleAll(items)

【讨论】:

codesandbox.io/s/morning-voice-qrym9?file=/src/TransferList.js -- 我设法显示了复选框 -- 但点击它们没有影响? 你在哪里 this.state = stuff here 我希望你想要 this.setState( stuff here ) (除了构造函数)。编辑:从您的代码和框链接的外观来看,它似乎在它认为这是一个问题的地方放置了一个黄色的波浪线。 好地方 - 好的 好的 - 我们现在接近了 - 复选框检查 - 但我似乎无法在左/右传输按钮上进行任何操作 - codesandbox.io/s/morning-voice-qrym9?file=/src/TransferList.js codesandbox.io/s/morning-voice-qrym9?file=/src/TransferList.js -- 搞定了 -- 谢谢大佬 -- 我们如何改进 -- 更紧凑 我要做的很多事情可能是相当主观的,但我会提到几件事:我可能会将 not、intersection 和 union 函数删除到类定义之外的某个地方——它们感觉就像不是特定于类的通用实用程序功能;我可能会分解左右函数(例如handleCheckedLeft),因为它们只是在不同的列表上做同样的事情;在 customList 中,我可能会计算 this.numberOfChecked(items) 一次(在 return 语句之前)。不过,我当然不是这方面的专家。

以上是关于React js - 材质 ui - 传输列表 - 使用旧状态的主要内容,如果未能解决你的问题,请参考以下文章

React - 网格内的材质 UI 项目拒绝居中

材质ui中的<Grid>导致水平滚动-React

使用 @testing-library/react 测试材质 ui 滑块

如何使用 react-dnd 从材质 UI 中拖放 TableHeaderColumn?

使用材质 ui 和 React,在 TextField 中更改 `carrot` 的样式

如何在 React JS 中使用聊天气泡制作像 UI 一样的聊天